Mercurial > hg > orthanc
changeset 5994:bad103ab55c5 attach-custom-data
merged default -> attach-custom-data
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.clang-format Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,57 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: true +AlignTrailingComments: false +AlwaysBreakTemplateDeclarations: Yes +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 200 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ContinuationIndentWidth: 2 +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +TabWidth: 2 +...
--- a/.hgignore Wed Oct 09 11:06:20 2024 +0200 +++ b/.hgignore Thu Jan 30 17:41:33 2025 +0100 @@ -7,6 +7,7 @@ .vscode/ *~ *.cmake.orig +.idea/ # when opening Orthanc in VSCode, it might find a java project and create files we wan't to ignore: .settings/
--- a/CITATION.cff Wed Oct 09 11:06:20 2024 +0200 +++ b/CITATION.cff Thu Jan 30 17:41:33 2025 +0100 @@ -10,5 +10,5 @@ doi: "10.1007/s10278-018-0082-y" license: "GPL-3.0-or-later" repository-code: "https://orthanc.uclouvain.be/hg/orthanc/" -version: 1.12.4 -date-released: 2024-06-05 +version: 1.12.6 +date-released: 2025-01-22
--- a/NEWS Wed Oct 09 11:06:20 2024 +0200 +++ b/NEWS Thu Jan 30 17:41:33 2025 +0100 @@ -10,82 +10,170 @@ - using multiple disk for image storage - use more human friendly storage structure (experimental feature) +REST API +-------- + +* API version upgraded to 28 + + Plugins ------- -* New database plugin SDK (v4) to handle customData for attachments. +* New database plugin SDK (vX) to handle customData for attachments. * New storage plugin SDK (v3) to handle customData for attachments, -* TODO-FIND: complete the list of updated routes: - - /studies?expand and sibbling routes now also return "Metadata" (if the DB implements 'extended-api-v1') - - /studies?since=x&limit=0 and sibbling routes: limit=0 now means "no limit" instead of "no results" + +Maintenance +----------- + +* In the "ExtendedFind" mode, optimized "tools/find" when "StorageAccessMode" is + set to "Never". + + +Version 1.12.6 (2025-01-22) +=========================== + +General +------- + +* DICOM: Added support for C-GET SCU. +* Added new configuration options: + - "AcceptedSopClasses" and "RejectedSopClasses" to limit the SOP classes + accepted by Orthanc when acting as C-STORE SCP. + - "DicomDefaultRetrieveMethod" to define whether Orthanc uses C-MOVE or + C-GET to retrieve a resource after a C-FIND (if calling "/queries/.../retrieve"). + This configuration can be overridden for each DICOM modality by setting + the "RetrieveMethod" field in the "DicomModalities" section. + Default value: "C-MOVE" to preserve backward compatibility. + - "MaximumConcurrentDcmtkTranscoders" to reduce CPU and memory usage by limiting + the number of concurrent DCMTK transcoders that are simultaneously running + at any given time. + +REST API +-------- + +* API version upgraded to 27 +* C-GET SCU requests can be triggered through the new route "/modalities/{id}/get" + +Plugins +------- + +* SDK: Added "OrthancPluginStartStreamAnswer()" and "OrthancPluginSendStreamChunk()" + to allow the sending of HTTP responses by chunks. + +Maintenance +----------- + +* Fix: In the "ExtendedFind" mode, using "tools/find" while querying against + "ModalitiesInStudy" was not compatible with pagination. This notably prevented + the use of the modality filter in Orthanc Explorer 2. +* If the "HttpsCACertificates" configuration is empty, Orthanc now uses the + operating system native CA store (if any). This is equivalent to the "--ca-native" + curl option. +* Housekeeper plugin: + - Fix the "Force" configuration that was ineffective. + - Allow transcoding to lossy transfer syntax. Orthanc will leave + the "SOPInstanceUID" DICOM tag untouched in this case. +* In the "/archive" routes: + - The numbers in the filenames now match the "InstanceNumber" tag whenever possible. + When not, the files are ordered in the same order as the instances in the series. + - Added optimization to use the "ExtendedFind" extension, hereby reducing the number + of SQL queries. +* DICOM negotiation: + - When opening a DICOM SCU connection, Orthanc now only proposes the contexts that it is + going to use in the connection, and not all the contexts as in previous versions + (e.g., if performing a C-ECHO, Orthanc will not propose C-MOVE or C-FIND). +* DICOM C-GET SCP: Orthanc will not refuse anymore to send, for instance, a + LittleEndianExplicit file, if the accepted transfer syntax is a compressed one. +* By default, DCMTK now uses its own "oficonv" library for character set conversion. + This can be tuned using the new CMake option "-DDCMTK_LOCALE_BACKEND=oficonv". +* Improved progress reporting for DicomMoveScu jobs. +* Upgraded dependencies for static builds: + - dcmtk 3.6.9 + + +Version 1.12.5 (2024-12-17) +=========================== General ------- * Database: - - Introduced database optimizations "ExtendedFind" to replace many small SQL queries - by a small number of large SQL queries to greatly reduce the cost of DB latency. - Furthermore, this "ExtendedFind" brings new sorting and filtering features to the - Rest API (TODO). - - Introduced database optimizations "ExtendedChanges" to allow filtering of /changes. + - Introduced the database optimization "ExtendedFind" to replace many small SQL queries + by a single, large SQL query. This can greatly reduce the cost related to latency + when working with large databases (e.g., if using PostgreSQL). + Furthermore, "ExtendedFind" brings new sorting and filtering features to the + REST API, mainly in "/tools/find". + - Introduced the new database primitive "ExtendedChanges" to allow filtering on "/changes". - Reduced the number of SQL queries when ingesting DICOM files. -* Introduced a new configuration "ReadOnly" to forbid an Orthanc instance to perform - any modifications in the Index DB or in the storage. +* Introduced a new configuration "ReadOnly" to forbid an Orthanc instance to perform + any modification to the index database or to the storage area. + REST API -------- -* API version upgraded to 25 -* Improved parsing of multiple numerical values in DICOM tags. +* API version upgraded to 26 +* Support HTTP "Range" request header on "{...}/attachments/{...}/data" and + "{...}/attachments/{...}/compressed-data" +* Improved parsing of multiple numerical values in DICOM tags https://discourse.orthanc-server.org/t/qido-includefield-with-sequences/4746/6 -* in /system, added a new field "Capabilities" with new values: - - "HasExtendedChanges" for DB backend that provides this feature (the default SQLite DB - or PostgreSQL vX.X, MySQL vX.X, ODBC vX.X). - - "HasExtendedFind" for DB backend that provides this feature (the default SQLite DB - or PostgreSQL vX.X, MySQL vX.X, ODBC vX.X). -* With DB backend with "HasExtendedChanges" support, /changes now supports 2 more options: - - 'type' to filter the changes returned by the query - - 'to' to potentially cycle through changes in reverse order. - example: /changes?type=StableStudy&to=7584&limit=100 -* With DB backend with "HasExtendedFind" support, /tools/find now supports new options: - - 'OrderBy' to order by DICOM Tag or metadata value - - 'ParentPatient', 'ParentStudy', 'ParentSeries' to retrieve only descendants of an - Orthanc resource. - - 'QueryMetadata' to filter results based on metadata values. - - 'ResponseContent' to define what shall be included in the response for each returned - resource (e.g: Metadata, Children, ...) - +* In "/system", added a new field "Capabilities" with new values: + - "HasExtendedChanges" if the index database provides this optimization + - "HasExtendedFind" if the index database provides this primitive +* If the index database provides the "HasExtendedChanges" primitive, "/changes" + supports two additional arguments: + - "type" to filter the changes returned by the query + - "to" to possibly cycle through changes in reverse order + Example: "/changes?type=StableStudy&to=7584&limit=100" +* If the index database provides the "HasExtendedFind" primitive, "/tools/find" + supports new options: + - "OrderBy" to order by DICOM tag or metadata value + - "ParentPatient", "ParentStudy", and "ParentSeries" to retrieve only descendants of a + given DICOM resource + - "MetadataQuery" to filter results based on metadata values + - "ResponseContent" to define what shall be included in the response for each returned + resource (e.g: Metadata, Children,...) +* In "/tools/find", the "Limit" and "Since" arguments are not allowed anymore if the + query requests filtering on DICOM tags that are not stored in the index database +* The new "/tools/count-resources" API route is similar to "tools/find" but only + returns the number of resources matching the criteria +* "/studies?since=x&limit=0" and similar routes for patients, series, and instances: + "limit=0" now means "no limit" instead of "no results" as in previous versions of Orthanc +* In DICOMweb JSON, the "DS - Decimal String" values were previously represented as float + numbers, but are now represented as strings to avoid introduction of long float representation + (e.g 0.1429999999999 vs "0.143") and to be compliant with the DICOMweb standard: + https://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.3.html + This has no impact on the Stone Web viewer and OHIF: + https://discourse.orthanc-server.org/t/dicomwebplugin-does-not-return-series-metadata-properly/5195 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. + an outgoing SCU connection if "DicomTlsRemoteCertificateRequired" is set to "false" +* Fix C-Find queries not returning computed tags such as ModalitiesInStudy, + NumberOfStudyRelatedSeries,... in very specific use cases +* Fix C-Find queries not returning private tags in the modality worklist plugin +* Fix an extremely rare error when 2 threads are trying to create the same folder + in the File Storage at the same time +* Fix crashes if handling very large images +* Fix deadlock when parsing specific invalid DICOM files +* Loading plugins: Orthanc will now fail to start when provided with a plugin path + that can not be found * 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 - - SQLite 3.46 + - Fix a few metrics that were not published + - Added 2 metrics: "orthanc_storage_cache_miss_count" and "orthanc_storage_cache_hit_count" * 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: + 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 new warnings that can be disabled in the configuration: - W003_DecoderFailure - W004_NoMainDicomTagsSignature - W005_RequestingTagFromLowerResourceLevel -* New default MainDicomTags are now stored in DB. Note that, in order to store these values - for resources that were ingested in Orthanc before this release, you would have to run - the Housekeeper plugin or call /reconstruct on every resources + - W006_RequestingTagFromMetaHeader + - W007_MissingRequestedTagsNotReadFromDisk +* New default MainDicomTags are now stored in the DB: - At Study Level: - TimezoneOffsetFromUTC (used in QIDO-RS default queries) - At Series Level: @@ -93,7 +181,13 @@ - PerformedProcedureStepStartDate (used in QIDO-RS default queries) - PerformedProcedureStepStartTime (used in QIDO-RS default queries) - RequestAttributesSequence (used in QIDO-RS default queries) - + - Note that, in order to access these values for resources that were ingested in Orthanc + before this release, you will have to run the Housekeeper plugin or to call + "/reconstruct" on every resource +* Upgraded dependencies for static builds: + - boost 1.86.0 + - curl 8.9.0 + - SQLite 3.46 Version 1.12.4 (2024-06-05) @@ -118,7 +212,7 @@ * 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. + up the housekeeper process, e.g. if you have only updated 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
--- a/OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/BoostConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/BoostConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -91,10 +91,10 @@ ## Parameters for static compilation of Boost ## - 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_NAME boost_1_86_0) + set(BOOST_VERSION 1.86.0) + set(BOOST_BCP_SUFFIX bcpdigest-1.12.5) + set(BOOST_MD5 "20b9c325c0dde830889ee75a9e64ded8") 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}) @@ -115,7 +115,7 @@ if (FirstRun) execute_process( COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${CMAKE_CURRENT_LIST_DIR}/../Patches/boost-1.85.0-emscripten.patch + ${CMAKE_CURRENT_LIST_DIR}/../Patches/boost-1.86.0-emscripten.patch WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE Failure )
--- a/OrthancFramework/Resources/CMake/BoostConfiguration.sh Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/BoostConfiguration.sh Thu Jan 30 17:41:33 2025 +0100 @@ -27,9 +27,10 @@ ## - Orthanc 1.12.2: Boost 1.83.0 ## - Orthanc 1.12.3: Boost 1.84.0 ## - Orthanc > 1.12.3: Boost 1.85.0 +## - Orthanc 1.12.5: Boost 1.86.0 -BOOST_VERSION=1_85_0 -ORTHANC_VERSION=1.12.4 +BOOST_VERSION=1_86_0 +ORTHANC_VERSION=1.12.5 rm -rf /tmp/boost_${BOOST_VERSION} rm -rf /tmp/bcp/boost_${BOOST_VERSION}
--- a/OrthancFramework/Resources/CMake/BoostConfigurationStatic-1.69.0.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/BoostConfigurationStatic-1.69.0.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/CivetwebConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/CivetwebConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/Compiler.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/Compiler.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -239,7 +239,9 @@ add_definitions( -D_XOPEN_SOURCE=1 ) - link_libraries(iconv) + + # Linking with iconv breaks the Universal builds on modern compilers + # link_libraries(iconv) elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") message("Building using Emscripten (for WebAssembly or asm.js targets)")
--- a/OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,6 +39,8 @@ 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) + elseif (DCMTK_STATIC_VERSION STREQUAL "3.6.9") + include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.9.cmake) else() message(FATAL_ERROR "Unsupported version of DCMTK: ${DCMTK_STATIC_VERSION}") endif() @@ -58,9 +60,9 @@ ) if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - message(${DCMTK_SOURCES_DIR}) list(REMOVE_ITEM DCMTK_SOURCES ${DCMTK_SOURCES_DIR}/ofstd/libsrc/offilsys.cc + ${DCMTK_SOURCES_DIR}/ofstd/libsrc/ofwhere.c # Needed since DCMTK 3.6.9 ) endif()
--- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.6.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.6.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.7.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.7.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.8.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.8.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.9.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,301 @@ +# 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-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +# <http://www.gnu.org/licenses/>. + + +SET(DCMTK_VERSION_NUMBER 369) +SET(DCMTK_PACKAGE_VERSION "3.6.9") +SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.9) +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.9.tar.gz") +SET(DCMTK_MD5 "cb30587f8da760c832a4f19d159acda5") + +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.9.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.9-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(GNUInstallDirs) # Needed since DCMTK 3.6.9 +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 DCMTK_LOCALE_BACKEND OR # This is the case if locale support is disabled (e.g. in Stone) + DCMTK_LOCALE_BACKEND STREQUAL "gcc") + set(DCMTK_ENABLE_CHARSET_CONVERSION "DCMTK_CHARSET_CONVERSION_STDLIBC_ICONV" CACHE STRING "" FORCE) +elseif (DCMTK_LOCALE_BACKEND STREQUAL "libiconv") + set(DCMTK_ENABLE_CHARSET_CONVERSION "DCMTK_CHARSET_CONVERSION_ICONV" CACHE STRING "" FORCE) +elseif (DCMTK_LOCALE_BACKEND STREQUAL "icu") + message(FATAL_ERROR "Support for ICU has been removed since DCMTK 3.6.9") +elseif (DCMTK_LOCALE_BACKEND STREQUAL "oficonv") + set(DCMTK_ENABLE_CHARSET_CONVERSION "DCMTK_CHARSET_CONVERSION_OFICONV" CACHE STRING "" FORCE) +else() + message(FATAL_ERROR "Invalid value for DCMTK_LOCALE_BACKEND: ${DCMTK_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" => Removed since DCMTK 3.6.9 +#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() + + if (CMAKE_COMPILER_IS_GNUCXX) # MinGW + # Necessary since DCMTK 3.6.9 + add_definitions( + -DENABLE_OLD_OFSTD_FTOA_IMPLEMENTATION + -DENABLE_OLD_OFSTD_ATOF_IMPLEMENTATION + ) + endif() +endif() + + +if (DCMTK_LOCALE_BACKEND STREQUAL "oficonv") + AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/oficonv/libsrc DCMTK_SOURCES) +endif()
--- a/OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -165,6 +165,10 @@ set(ORTHANC_FRAMEWORK_MD5 "975f5bf2142c22cb1777b4f6a0a614c5") elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.4") set(ORTHANC_FRAMEWORK_MD5 "1e61779ea4a7cd705720bdcfed8a6a73") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.5") + set(ORTHANC_FRAMEWORK_MD5 "5bb69f092981fdcfc11dec0a0f9a7db3") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.6") + set(ORTHANC_FRAMEWORK_MD5 "0e971f32f4f3e4951e0f3b5de49a3da6") # Below this point are development snapshots that were used to # release some plugin, before an official release of the Orthanc
--- a/OrthancFramework/Resources/CMake/DownloadPackage.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/DownloadPackage.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/EmscriptenParameters.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/EmscriptenParameters.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/GoogleTestConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/GoogleTestConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/JsonCppConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/JsonCppConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/LibCurlConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/LibCurlConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/LibIconvConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/LibIconvConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/LibIcuConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/LibIcuConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/LibJpegConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/LibJpegConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/LibP11Configuration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/LibP11Configuration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/LibPngConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/LibPngConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/LuaConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/LuaConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/MongooseConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/MongooseConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/OpenSslConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/OpenSslConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-3.0.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-3.0.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -456,7 +456,8 @@ # is shipped with the stdlib unset(BOOST_LOCALE_BACKEND CACHE) else() - if (BOOST_LOCALE_BACKEND STREQUAL "gcc") + if (BOOST_LOCALE_BACKEND STREQUAL "gcc" OR + BOOST_LOCALE_BACKEND STREQUAL "oficonv") elseif (BOOST_LOCALE_BACKEND STREQUAL "libiconv") include(${CMAKE_CURRENT_LIST_DIR}/LibIconvConfiguration.cmake) elseif (BOOST_LOCALE_BACKEND STREQUAL "icu")
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +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 "25") +set(ORTHANC_API_VERSION "28") ##################################################################### @@ -79,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.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(DCMTK_STATIC_VERSION "3.6.9" 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\", \"3.6.8\", or \"3.6.9\")") 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") @@ -90,6 +90,7 @@ set(USE_GOOGLE_TEST_DEBIAN_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)") set(SYSTEM_MONGOOSE_USE_CALLBACKS ON CACHE BOOL "The system version of Mongoose uses callbacks (version >= 3.7)") set(BOOST_LOCALE_BACKEND "libiconv" CACHE STRING "Back-end for locales that is used by Boost (can be \"gcc\", \"libiconv\", \"icu\", or \"wconv\" on Windows)") +set(DCMTK_LOCALE_BACKEND "oficonv" CACHE STRING "Back-end for locales that is used by DCMTK (can be \"gcc\", \"libiconv\", \"icu\" (only up to DCMTK 3.6.8), \"oficonv\")") set(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)") set(USE_LEGACY_JSONCPP OFF CACHE BOOL "Use the old branch 0.x.y of JsonCpp, that does not require a C++11 compiler (for LSB and old versions of Visual Studio)") set(USE_LEGACY_LIBICU OFF CACHE BOOL "Use icu icu4c-58_2, latest version not requiring a C++11 compiler (for LSB and old versions of Visual Studio)")
--- a/OrthancFramework/Resources/CMake/ProtobufConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/ProtobufConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/PugixmlConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/PugixmlConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/SQLiteConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/SQLiteConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,16 +20,7 @@ # <http://www.gnu.org/licenses/>. -if (APPLE) - # Under OS X, the binaries must always be linked against the - # system-wide version of SQLite. Otherwise, if some Orthanc plugin - # also uses its own version of SQLite (such as orthanc-webviewer), - # this results in a crash in "sqlite3_mutex_enter(db->mutex);" (the - # mutex is not initialized), probably because the EXE and the DYNLIB - # share the same memory location for this mutex. - set(SQLITE_STATIC OFF) - -elseif (STATIC_BUILD OR NOT USE_SYSTEM_SQLITE) +if (STATIC_BUILD OR NOT USE_SYSTEM_SQLITE) set(SQLITE_STATIC ON) else() set(SQLITE_STATIC OFF)
--- a/OrthancFramework/Resources/CMake/UuidConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/UuidConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/VisualStudioPrecompiledHeaders.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/VisualStudioPrecompiledHeaders.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/WebAssembly/ArithmeticTests/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/WebAssembly/ArithmeticTests/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CMake/ZlibConfiguration.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CMake/ZlibConfiguration.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CheckOrthancFrameworkSymbols.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CheckOrthancFrameworkSymbols.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CodeGeneration/CheckDcmtkTransferSyntaxes.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/CheckDcmtkTransferSyntaxes.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CodeGeneration/ErrorCodes.json Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/ErrorCodes.json Thu Jan 30 17:41:33 2025 +0100 @@ -607,6 +607,11 @@ "Name": "NoCGetHandler", "Description": "No request handler factory for DICOM C-GET SCP" }, + { + "Code": 2045, + "Name": "DicomGetUnavailable", + "Description": "DicomUserConnection: The C-GET command is not supported by the remote SCP" + },
--- a/OrthancFramework/Resources/CodeGeneration/GenerateErrorCodes.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateErrorCodes.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxes.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxes.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesDcmtk.mustache Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesDcmtk.mustache Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesEnumerations.mustache Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesEnumerations.mustache Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/DcmtkTools/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/DcmtkTools/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/DcmtkTools/dummy.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/DcmtkTools/dummy.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/EmbedResources.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/EmbedResources.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Graveyard/EclipseCodingStyle.xml Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<profiles version="1"> -<profile kind="CodeFormatterProfile" name="Orthanc" version="1"> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.lineSplit" value="80"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_member_access" value="0"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_constructor_initializer_list" value="0"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.comment.min_distance_between_code_and_line_comment" value="1"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer" value="18"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.tabulation.size" value="2"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_enumerator_list" value="49"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_declarator_list" value="16"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.indent_empty_lines" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.brace_position_for_method_declaration" value="next_line"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.join_wrapped_lines" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation" value="18"/> -<setting id="org.eclipse.cdt.core.formatter.comment.never_indent_line_comments_on_first_column" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration" value="18"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block" value="next_line"/> -<setting id="org.eclipse.cdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.brace_position_for_type_declaration" value="next_line"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.continuation_indentation" value="2"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_expression_list" value="0"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_binary_operator" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression" value="34"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_extra_spaces" value="0"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_compact_if" value="16"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_assignment" value="16"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression_chain" value="18"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_binary_operator" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration" value="80"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_body" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_binary_expression" value="18"/> -<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_block" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.tabulation.char" value="space"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_colon_in_constructor_initializer_list" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block_in_case" value="next_line"/> -<setting id="org.eclipse.cdt.core.formatter.compact_else_if" value="true"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.brace_position_for_switch" value="next_line"/> -<setting id="org.eclipse.cdt.core.formatter.alignment_for_overloaded_left_shift_chain" value="18"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line" value="false"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.indentation.size" value="2"/> -<setting id="org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration" value="next_line"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.brace_position_for_array_initializer" value="next_line"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket" value="do not insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters" value="insert"/> -<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments" value="do not insert"/> -</profile> -</profiles>
--- a/OrthancFramework/Resources/Graveyard/FromDcmtkBridge.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - - DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag) - { - DcmTag key(tag.GetGroup(), tag.GetElement()); - - if (tag.IsPrivate()) - { - // This raises BitBucket issue 140 (Modifying private tags with - // REST API changes VR from LO to UN) - // 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); - } - else if (IsBinaryTag(key)) - { - return new DcmOtherByteOtherWord(key); - } - - switch (key.getEVR()) - { - // http://support.dcmtk.org/docs/dcvr_8h-source.html - - /** - * Binary types, handled above - **/ - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_OD: -#endif - -#if DCMTK_VERSION_NUMBER >= 362 - case EVR_OL: -#endif - - case EVR_OB: // other byte - case EVR_OF: // other float - case EVR_OW: // other word - case EVR_UN: // unknown value representation - case EVR_ox: // OB or OW depending on context - throw OrthancException(ErrorCode_InternalError); - - - /** - * String types. - * http://support.dcmtk.org/docs/classDcmByteString.html - **/ - - case EVR_AS: // age string - return new DcmAgeString(key); - - case EVR_AE: // application entity title - return new DcmApplicationEntity(key); - - case EVR_CS: // code string - return new DcmCodeString(key); - - case EVR_DA: // date string - return new DcmDate(key); - - case EVR_DT: // date time string - return new DcmDateTime(key); - - case EVR_DS: // decimal string - return new DcmDecimalString(key); - - case EVR_IS: // integer string - return new DcmIntegerString(key); - - case EVR_TM: // time string - return new DcmTime(key); - - case EVR_UI: // unique identifier - return new DcmUniqueIdentifier(key); - - case EVR_ST: // short text - return new DcmShortText(key); - - case EVR_LO: // long string - return new DcmLongString(key); - - case EVR_LT: // long text - return new DcmLongText(key); - - case EVR_UT: // unlimited text - return new DcmUnlimitedText(key); - - case EVR_SH: // short string - return new DcmShortString(key); - - case EVR_PN: // person name - return new DcmPersonName(key); - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_UC: // unlimited characters - return new DcmUnlimitedCharacters(key); -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_UR: // URI/URL - return new DcmUniversalResourceIdentifierOrLocator(key); -#endif - - - /** - * Numerical types - **/ - - case EVR_SL: // signed long - return new DcmSignedLong(key); - - case EVR_SS: // signed short - return new DcmSignedShort(key); - - case EVR_UL: // unsigned long - return new DcmUnsignedLong(key); - - case EVR_US: // unsigned short - return new DcmUnsignedShort(key); - - case EVR_FL: // float single-precision - return new DcmFloatingPointSingle(key); - - case EVR_FD: // float double-precision - return new DcmFloatingPointDouble(key); - - - /** - * Sequence types, should never occur at this point. - **/ - - case EVR_SQ: // sequence of items - throw OrthancException(ErrorCode_ParameterOutOfRange); - - - /** - * TODO - **/ - - case EVR_AT: // attribute tag - throw OrthancException(ErrorCode_NotImplemented); - - - /** - * Internal to DCMTK. - **/ - - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR - default: - break; - } - - throw OrthancException(ErrorCode_InternalError); - }
--- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasks.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../ICommand.h" - -#include <list> -#include <cstddef> - -namespace Orthanc -{ - class BagOfTasks : public boost::noncopyable - { - private: - typedef std::list<ICommand*> Tasks; - - Tasks tasks_; - - public: - ~BagOfTasks() - { - for (Tasks::iterator it = tasks_.begin(); it != tasks_.end(); ++it) - { - delete *it; - } - } - - ICommand* Pop() - { - ICommand* task = tasks_.front(); - tasks_.pop_front(); - return task; - } - - void Push(ICommand* task) // Takes ownership - { - if (task != NULL) - { - tasks_.push_back(task); - } - } - - size_t GetSize() const - { - return tasks_.size(); - } - - bool IsEmpty() const - { - return tasks_.empty(); - } - }; -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "BagOfTasksProcessor.h" - -#include "../Logging.h" -#include "../OrthancException.h" - -#include <stdio.h> - -namespace Orthanc -{ - class BagOfTasksProcessor::Task : public IDynamicObject - { - private: - uint64_t bag_; - std::auto_ptr<ICommand> command_; - - public: - Task(uint64_t bag, - ICommand* command) : - bag_(bag), - command_(command) - { - } - - bool Execute() - { - try - { - return command_->Execute(); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception while processing a bag of tasks: " << e.What(); - return false; - } - catch (std::runtime_error& e) - { - LOG(ERROR) << "Runtime exception while processing a bag of tasks: " << e.what(); - return false; - } - catch (...) - { - LOG(ERROR) << "Native exception while processing a bag of tasks"; - return false; - } - } - - uint64_t GetBag() - { - return bag_; - } - }; - - - void BagOfTasksProcessor::SignalProgress(Task& task, - Bag& bag) - { - assert(bag.done_ < bag.size_); - - bag.done_ += 1; - - if (bag.done_ == bag.size_) - { - exitStatus_[task.GetBag()] = (bag.status_ == BagStatus_Running); - bagFinished_.notify_all(); - } - } - - void BagOfTasksProcessor::Worker(BagOfTasksProcessor* that) - { - while (that->continue_) - { - std::auto_ptr<IDynamicObject> obj(that->queue_.Dequeue(100)); - if (obj.get() != NULL) - { - Task& task = *dynamic_cast<Task*>(obj.get()); - - { - boost::mutex::scoped_lock lock(that->mutex_); - - Bags::iterator bag = that->bags_.find(task.GetBag()); - assert(bag != that->bags_.end()); - assert(bag->second.done_ < bag->second.size_); - - if (bag->second.status_ != BagStatus_Running) - { - // Do not execute this task, as its parent bag of tasks - // has failed or is tagged as canceled - that->SignalProgress(task, bag->second); - continue; - } - } - - bool success = task.Execute(); - - { - boost::mutex::scoped_lock lock(that->mutex_); - - Bags::iterator bag = that->bags_.find(task.GetBag()); - assert(bag != that->bags_.end()); - - if (!success) - { - bag->second.status_ = BagStatus_Failed; - } - - that->SignalProgress(task, bag->second); - } - } - } - } - - - void BagOfTasksProcessor::Cancel(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - Bags::iterator it = bags_.find(bag); - if (it != bags_.end()) - { - it->second.status_ = BagStatus_Canceled; - } - } - - - bool BagOfTasksProcessor::Join(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - while (continue_) - { - ExitStatus::iterator it = exitStatus_.find(bag); - if (it == exitStatus_.end()) // The bag is still running - { - bagFinished_.wait(lock); - } - else - { - bool status = it->second; - exitStatus_.erase(it); - return status; - } - } - - return false; // The processor is stopping - } - - - float BagOfTasksProcessor::GetProgress(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - Bags::const_iterator it = bags_.find(bag); - if (it == bags_.end()) - { - // The bag of tasks has finished - return 1.0f; - } - else - { - return (static_cast<float>(it->second.done_) / - static_cast<float>(it->second.size_)); - } - } - - - bool BagOfTasksProcessor::Handle::Join() - { - if (hasJoined_) - { - return status_; - } - else - { - status_ = that_.Join(bag_); - hasJoined_ = true; - return status_; - } - } - - - BagOfTasksProcessor::BagOfTasksProcessor(size_t countThreads) : - countBags_(0), - continue_(true) - { - if (countThreads == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - threads_.resize(countThreads); - - for (size_t i = 0; i < threads_.size(); i++) - { - threads_[i] = new boost::thread(Worker, this); - } - } - - - BagOfTasksProcessor::~BagOfTasksProcessor() - { - continue_ = false; - - bagFinished_.notify_all(); // Wakes up all the pending "Join()" - - for (size_t i = 0; i < threads_.size(); i++) - { - if (threads_[i]) - { - if (threads_[i]->joinable()) - { - threads_[i]->join(); - } - - delete threads_[i]; - threads_[i] = NULL; - } - } - } - - - BagOfTasksProcessor::Handle* BagOfTasksProcessor::Submit(BagOfTasks& tasks) - { - if (tasks.GetSize() == 0) - { - return new Handle(*this, 0, true); - } - - boost::mutex::scoped_lock lock(mutex_); - - uint64_t id = countBags_; - countBags_ += 1; - - Bag bag(tasks.GetSize()); - bags_[id] = bag; - - while (!tasks.IsEmpty()) - { - queue_.Enqueue(new Task(id, tasks.Pop())); - } - - return new Handle(*this, id, false); - } -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "BagOfTasks.h" -#include "SharedMessageQueue.h" - -#include <stdint.h> -#include <map> - -namespace Orthanc -{ - class BagOfTasksProcessor : public boost::noncopyable - { - private: - enum BagStatus - { - BagStatus_Running, - BagStatus_Canceled, - BagStatus_Failed - }; - - - struct Bag - { - size_t size_; - size_t done_; - BagStatus status_; - - Bag() : - size_(0), - done_(0), - status_(BagStatus_Failed) - { - } - - explicit Bag(size_t size) : - size_(size), - done_(0), - status_(BagStatus_Running) - { - } - }; - - class Task; - - - typedef std::map<uint64_t, Bag> Bags; - typedef std::map<uint64_t, bool> ExitStatus; - - SharedMessageQueue queue_; - - boost::mutex mutex_; - uint64_t countBags_; - Bags bags_; - std::vector<boost::thread*> threads_; - ExitStatus exitStatus_; - bool continue_; - - boost::condition_variable bagFinished_; - - static void Worker(BagOfTasksProcessor* that); - - void Cancel(int64_t bag); - - bool Join(int64_t bag); - - float GetProgress(int64_t bag); - - void SignalProgress(Task& task, - Bag& bag); - - public: - class Handle : public boost::noncopyable - { - friend class BagOfTasksProcessor; - - private: - BagOfTasksProcessor& that_; - uint64_t bag_; - bool hasJoined_; - bool status_; - - Handle(BagOfTasksProcessor& that, - uint64_t bag, - bool empty) : - that_(that), - bag_(bag), - hasJoined_(empty) - { - } - - public: - ~Handle() - { - Join(); - } - - void Cancel() - { - that_.Cancel(bag_); - } - - bool Join(); - - float GetProgress() - { - return that_.GetProgress(bag_); - } - }; - - - explicit BagOfTasksProcessor(size_t countThreads); - - ~BagOfTasksProcessor(); - - Handle* Submit(BagOfTasks& tasks); - }; -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/ICommand.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "IDynamicObject.h" - -namespace Orthanc -{ - /** - * This class is the base class for the "Command" design pattern. - * http://en.wikipedia.org/wiki/Command_pattern - **/ - class ICommand : public IDynamicObject - { - public: - virtual bool Execute() = 0; - }; -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/ILockable.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include <boost/noncopyable.hpp> - -namespace Orthanc -{ - class ILockable : public boost::noncopyable - { - friend class Locker; - - protected: - virtual void Lock() = 0; - - virtual void Unlock() = 0; - - public: - virtual ~ILockable() - { - } - }; -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/Locker.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ILockable.h" - -namespace Orthanc -{ - class Locker : public boost::noncopyable - { - private: - ILockable& lockable_; - - public: - Locker(ILockable& lockable) : lockable_(lockable) - { - lockable_.Lock(); - } - - virtual ~Locker() - { - lockable_.Unlock(); - } - }; -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "Mutex.h" - -#include "../OrthancException.h" - -#if defined(_WIN32) -#include <windows.h> -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) -#include <pthread.h> -#else -#error Support your platform here -#endif - -namespace Orthanc -{ -#if defined (_WIN32) - - struct Mutex::PImpl - { - CRITICAL_SECTION criticalSection_; - }; - - Mutex::Mutex() - { - pimpl_ = new PImpl; - ::InitializeCriticalSection(&pimpl_->criticalSection_); - } - - Mutex::~Mutex() - { - ::DeleteCriticalSection(&pimpl_->criticalSection_); - delete pimpl_; - } - - void Mutex::Lock() - { - ::EnterCriticalSection(&pimpl_->criticalSection_); - } - - void Mutex::Unlock() - { - ::LeaveCriticalSection(&pimpl_->criticalSection_); - } - - -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) - - struct Mutex::PImpl - { - pthread_mutex_t mutex_; - }; - - Mutex::Mutex() - { - pimpl_ = new PImpl; - - if (pthread_mutex_init(&pimpl_->mutex_, NULL) != 0) - { - delete pimpl_; - throw OrthancException(ErrorCode_InternalError); - } - } - - Mutex::~Mutex() - { - pthread_mutex_destroy(&pimpl_->mutex_); - delete pimpl_; - } - - void Mutex::Lock() - { - if (pthread_mutex_lock(&pimpl_->mutex_) != 0) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - void Mutex::Unlock() - { - if (pthread_mutex_unlock(&pimpl_->mutex_) != 0) - { - throw OrthancException(ErrorCode_InternalError); - } - } - -#else -#error Support your plateform here -#endif -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ILockable.h" - -namespace Orthanc -{ - class Mutex : public ILockable - { - private: - struct PImpl; - - PImpl *pimpl_; - - protected: - virtual void Lock(); - - virtual void Unlock(); - - public: - Mutex(); - - ~Mutex(); - }; -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "ReaderWriterLock.h" - -#include <boost/thread/shared_mutex.hpp> - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation - // modules. - - class ReaderLockable : public ILockable - { - private: - boost::shared_mutex& lock_; - - protected: - virtual void Lock() - { - lock_.lock_shared(); - } - - virtual void Unlock() - { - lock_.unlock_shared(); - } - - public: - explicit ReaderLockable(boost::shared_mutex& lock) : lock_(lock) - { - } - }; - - - class WriterLockable : public ILockable - { - private: - boost::shared_mutex& lock_; - - protected: - virtual void Lock() - { - lock_.lock(); - } - - virtual void Unlock() - { - lock_.unlock(); - } - - public: - explicit WriterLockable(boost::shared_mutex& lock) : lock_(lock) - { - } - }; - } - - struct ReaderWriterLock::PImpl - { - boost::shared_mutex lock_; - ReaderLockable reader_; - WriterLockable writer_; - - PImpl() : reader_(lock_), writer_(lock_) - { - } - }; - - - ReaderWriterLock::ReaderWriterLock() - { - pimpl_ = new PImpl; - } - - - ReaderWriterLock::~ReaderWriterLock() - { - delete pimpl_; - } - - - ILockable& ReaderWriterLock::ForReader() - { - return pimpl_->reader_; - } - - - ILockable& ReaderWriterLock::ForWriter() - { - return pimpl_->writer_; - } -}
--- a/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ILockable.h" - -#include <boost/noncopyable.hpp> - -namespace Orthanc -{ - class ReaderWriterLock : public boost::noncopyable - { - private: - struct PImpl; - - PImpl *pimpl_; - - public: - ReaderWriterLock(); - - virtual ~ReaderWriterLock(); - - ILockable& ForReader(); - - ILockable& ForWriter(); - }; -}
--- a/OrthancFramework/Resources/Graveyard/TestTranscoding.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,991 +0,0 @@ -/** - * 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 - * <http://www.gnu.org/licenses/>. - **/ - - - bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, - DcmFileFormat& dicom, - DicomTransferSyntax syntax) - { - E_TransferSyntax xfer; - if (!LookupDcmtkTransferSyntax(xfer, syntax)) - { - return false; - } - else if (!dicom.validateMetaInfo(xfer).good()) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot setup the transfer syntax to write a DICOM instance"); - } - else - { - return SaveToMemoryBufferInternal(buffer, dicom, xfer); - } - } - - - bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, - DcmFileFormat& dicom) - { - E_TransferSyntax xfer = dicom.getDataset()->getCurrentXfer(); - if (xfer == EXS_Unknown) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot write a DICOM instance with unknown transfer syntax"); - } - else if (!dicom.validateMetaInfo(xfer).good()) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot setup the transfer syntax to write a DICOM instance"); - } - else - { - return SaveToMemoryBufferInternal(buffer, dicom, xfer); - } - } - - - - - -#include <dcmtk/dcmdata/dcostrmb.h> -#include <dcmtk/dcmdata/dcpixel.h> -#include <dcmtk/dcmdata/dcpxitem.h> - -#include "../Core/DicomParsing/Internals/DicomFrameIndex.h" - -namespace Orthanc -{ - class IParsedDicomImage : public boost::noncopyable - { - public: - virtual ~IParsedDicomImage() - { - } - - virtual DicomTransferSyntax GetTransferSyntax() = 0; - - virtual std::string GetSopClassUid() = 0; - - virtual std::string GetSopInstanceUid() = 0; - - virtual unsigned int GetFramesCount() = 0; - - // Can return NULL, for compressed transfer syntaxes - virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) = 0; - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) = 0; - - virtual void WriteToMemoryBuffer(std::string& target) = 0; - }; - - - class IDicomImageReader : public boost::noncopyable - { - public: - virtual ~IDicomImageReader() - { - } - - virtual IParsedDicomImage* Read(const void* data, - size_t size) = 0; - - virtual IParsedDicomImage* Transcode(const void* data, - size_t size, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) = 0; - }; - - - class DcmtkImageReader : public IDicomImageReader - { - private: - class Image : public IParsedDicomImage - { - private: - std::unique_ptr<DcmFileFormat> dicom_; - std::unique_ptr<DicomFrameIndex> index_; - DicomTransferSyntax transferSyntax_; - std::string sopClassUid_; - std::string sopInstanceUid_; - - static std::string GetStringTag(DcmDataset& dataset, - const DcmTagKey& tag) - { - const char* value = NULL; - - if (!dataset.findAndGetString(tag, value).good() || - value == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing SOP class/instance UID in DICOM instance"); - } - else - { - return std::string(value); - } - } - - public: - Image(DcmFileFormat* dicom, - DicomTransferSyntax syntax) : - dicom_(dicom), - transferSyntax_(syntax) - { - if (dicom == NULL || - dicom_->getDataset() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - DcmDataset& dataset = *dicom_->getDataset(); - index_.reset(new DicomFrameIndex(dataset)); - - sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID); - sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID); - } - - virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE - { - return transferSyntax_; - } - - virtual std::string GetSopClassUid() ORTHANC_OVERRIDE - { - return sopClassUid_; - } - - virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE - { - return sopInstanceUid_; - } - - virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE - { - return index_->GetFramesCount(); - } - - virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE - { - assert(dicom_.get() != NULL); - if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, transferSyntax_)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot write the DICOM instance to a memory buffer"); - } - } - - virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) ORTHANC_OVERRIDE - { - assert(dicom_.get() != NULL && - dicom_->getDataset() != NULL); - return DicomImageDecoder::Decode(*dicom_->getDataset(), frame); - } - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) ORTHANC_OVERRIDE - { - assert(index_.get() != NULL); - index_->GetRawFrame(target, frame); - } - }; - - unsigned int lossyQuality_; - - static DicomTransferSyntax DetectTransferSyntax(DcmFileFormat& dicom) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DcmDataset& dataset = *dicom.getDataset(); - - E_TransferSyntax xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - dataset.updateOriginalXfer(); - xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the transfer syntax of the DICOM instance"); - } - } - - DicomTransferSyntax syntax; - if (FromDcmtkBridge::LookupOrthancTransferSyntax(syntax, xfer)) - { - return syntax; - } - else - { - throw OrthancException( - ErrorCode_BadFileFormat, - "Unsupported transfer syntax: " + boost::lexical_cast<std::string>(xfer)); - } - } - - - static uint16_t GetBitsStored(DcmFileFormat& dicom) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - uint16_t bitsStored; - if (dicom.getDataset()->findAndGetUint16(DCM_BitsStored, bitsStored).good()) - { - return bitsStored; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing \"Bits Stored\" tag in DICOM instance"); - } - } - - - public: - DcmtkImageReader() : - lossyQuality_(90) - { - } - - void SetLossyQuality(unsigned int quality) - { - if (quality <= 0 || - quality > 100) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - lossyQuality_ = quality; - } - } - - unsigned int GetLossyQuality() const - { - return lossyQuality_; - } - - virtual IParsedDicomImage* Read(const void* data, - size_t size) - { - std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size)); - if (dicom.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - DicomTransferSyntax transferSyntax = DetectTransferSyntax(*dicom); - - return new Image(dicom.release(), transferSyntax); - } - - virtual IParsedDicomImage* Transcode(const void* data, - size_t size, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) - { - std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size)); - if (dicom.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - const uint16_t bitsStored = GetBitsStored(*dicom); - - if (syntax == DetectTransferSyntax(*dicom)) - { - // No transcoding is needed - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_LittleEndianImplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_LittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_BigEndianExplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - - if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) - { - return new Image(dicom.release(), syntax); - } - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess1 && - allowNewSopInstanceUid && - bitsStored == 8) - { - DJ_RPLossy rpLossy(lossyQuality_); - - if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess1, &rpLossy)) - { - return new Image(dicom.release(), syntax); - } - } -#endif - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess2_4 && - allowNewSopInstanceUid && - bitsStored <= 12) - { - DJ_RPLossy rpLossy(lossyQuality_); - if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess2_4, &rpLossy)) - { - return new Image(dicom.release(), syntax); - } - } -#endif - - //LOG(INFO) << "Unable to transcode DICOM image using the built-in reader"; - return NULL; - } - }; - - - - class IDicomTranscoder1 : public boost::noncopyable - { - public: - virtual ~IDicomTranscoder1() - { - } - - virtual DcmFileFormat& GetDicom() = 0; - - virtual DicomTransferSyntax GetTransferSyntax() = 0; - - virtual std::string GetSopClassUid() = 0; - - virtual std::string GetSopInstanceUid() = 0; - - virtual unsigned int GetFramesCount() = 0; - - virtual ImageAccessor* DecodeFrame(unsigned int frame) = 0; - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) = 0; - - // NB: Transcoding can change the value of "GetSopInstanceUid()" - // and "GetTransferSyntax()" if lossy compression is applied - virtual bool Transcode(std::string& target, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) = 0; - - virtual void WriteToMemoryBuffer(std::string& target) = 0; - }; - - - class DcmtkTranscoder2 : public IDicomTranscoder1 - { - private: - std::unique_ptr<DcmFileFormat> dicom_; - std::unique_ptr<DicomFrameIndex> index_; - DicomTransferSyntax transferSyntax_; - std::string sopClassUid_; - std::string sopInstanceUid_; - uint16_t bitsStored_; - unsigned int lossyQuality_; - - static std::string GetStringTag(DcmDataset& dataset, - const DcmTagKey& tag) - { - const char* value = NULL; - - if (!dataset.findAndGetString(tag, value).good() || - value == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing SOP class/instance UID in DICOM instance"); - } - else - { - return std::string(value); - } - } - - void Setup(DcmFileFormat* dicom) - { - lossyQuality_ = 90; - - dicom_.reset(dicom); - - if (dicom == NULL || - dicom_->getDataset() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - DcmDataset& dataset = *dicom_->getDataset(); - index_.reset(new DicomFrameIndex(dataset)); - - E_TransferSyntax xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - dataset.updateOriginalXfer(); - xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the transfer syntax of the DICOM instance"); - } - } - - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transferSyntax_, xfer)) - { - throw OrthancException( - ErrorCode_BadFileFormat, - "Unsupported transfer syntax: " + boost::lexical_cast<std::string>(xfer)); - } - - if (!dataset.findAndGetUint16(DCM_BitsStored, bitsStored_).good()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing \"Bits Stored\" tag in DICOM instance"); - } - - sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID); - sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID); - } - - public: - DcmtkTranscoder2(DcmFileFormat* dicom) // Takes ownership - { - Setup(dicom); - } - - DcmtkTranscoder2(const void* dicom, - size_t size) - { - Setup(FromDcmtkBridge::LoadFromMemoryBuffer(dicom, size)); - } - - void SetLossyQuality(unsigned int quality) - { - if (quality <= 0 || - quality > 100) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - lossyQuality_ = quality; - } - } - - unsigned int GetLossyQuality() const - { - return lossyQuality_; - } - - unsigned int GetBitsStored() const - { - return bitsStored_; - } - - virtual DcmFileFormat& GetDicom() - { - assert(dicom_ != NULL); - return *dicom_; - } - - virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE - { - return transferSyntax_; - } - - virtual std::string GetSopClassUid() ORTHANC_OVERRIDE - { - return sopClassUid_; - } - - virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE - { - return sopInstanceUid_; - } - - virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE - { - return index_->GetFramesCount(); - } - - virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE - { - if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot write the DICOM instance to a memory buffer"); - } - } - - virtual ImageAccessor* DecodeFrame(unsigned int frame) ORTHANC_OVERRIDE - { - assert(dicom_->getDataset() != NULL); - return DicomImageDecoder::Decode(*dicom_->getDataset(), frame); - } - - virtual void GetCompressedFrame(std::string& target, - unsigned int frame) ORTHANC_OVERRIDE - { - index_->GetRawFrame(target, frame); - } - - virtual bool Transcode(std::string& target, - DicomTransferSyntax syntax, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE - { - assert(dicom_ != NULL && - dicom_->getDataset() != NULL); - - if (syntax == GetTransferSyntax()) - { - printf("NO TRANSCODING\n"); - - // No change in the transfer syntax => simply serialize the current dataset - WriteToMemoryBuffer(target); - return true; - } - - printf(">> %d\n", bitsStored_); - - if (syntax == DicomTransferSyntax_LittleEndianImplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_LittleEndianImplicit; - return true; - } - - if (syntax == DicomTransferSyntax_LittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_LittleEndianExplicit; - return true; - } - - if (syntax == DicomTransferSyntax_BigEndianExplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_BigEndianExplicit; - return true; - } - - if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit && - FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_DeflatedLittleEndianExplicit; - return true; - } - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess1 && - allowNewSopInstanceUid && - GetBitsStored() == 8) - { - DJ_RPLossy rpLossy(lossyQuality_); - - if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_JPEGProcess1; - sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID); - return true; - } - } -#endif - -#if ORTHANC_ENABLE_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess2_4 && - allowNewSopInstanceUid && - GetBitsStored() <= 12) - { - DJ_RPLossy rpLossy(lossyQuality_); - if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) && - FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax)) - { - transferSyntax_ = DicomTransferSyntax_JPEGProcess2_4; - sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID); - return true; - } - } -#endif - - return false; - } - }; -} - - - - -#include <boost/filesystem.hpp> - - -static void TestFile(const std::string& path) -{ - static unsigned int count = 0; - count++; - - - printf("** %s\n", path.c_str()); - - std::string s; - SystemToolbox::ReadFile(s, path); - - Orthanc::DcmtkTranscoder2 transcoder(s.c_str(), s.size()); - - /*if (transcoder.GetBitsStored() != 8) // TODO - return; */ - - { - char buf[1024]; - sprintf(buf, "/tmp/source-%06d.dcm", count); - printf(">> %s\n", buf); - Orthanc::SystemToolbox::WriteFile(s, buf); - } - - printf("[%s] [%s] [%s] %d %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()), - transcoder.GetSopClassUid().c_str(), transcoder.GetSopInstanceUid().c_str(), - transcoder.GetFramesCount(), transcoder.GetTransferSyntax()); - - for (size_t i = 0; i < transcoder.GetFramesCount(); i++) - { - std::string f; - transcoder.GetCompressedFrame(f, i); - - if (i == 0) - { - char buf[1024]; - sprintf(buf, "/tmp/frame-%06d.raw", count); - printf(">> %s\n", buf); - Orthanc::SystemToolbox::WriteFile(f, buf); - } - } - - { - std::string t; - transcoder.WriteToMemoryBuffer(t); - - Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size()); - printf(">> %d %d ; %lu bytes\n", transcoder.GetTransferSyntax(), transcoder2.GetTransferSyntax(), t.size()); - } - - { - std::string a = transcoder.GetSopInstanceUid(); - DicomTransferSyntax b = transcoder.GetTransferSyntax(); - - DicomTransferSyntax syntax = DicomTransferSyntax_JPEGProcess2_4; - //DicomTransferSyntax syntax = DicomTransferSyntax_LittleEndianExplicit; - - std::string t; - bool ok = transcoder.Transcode(t, syntax, true); - printf("Transcoding: %d\n", ok); - - if (ok) - { - printf("[%s] => [%s]\n", a.c_str(), transcoder.GetSopInstanceUid().c_str()); - printf("[%s] => [%s]\n", GetTransferSyntaxUid(b), - GetTransferSyntaxUid(transcoder.GetTransferSyntax())); - - { - char buf[1024]; - sprintf(buf, "/tmp/transcoded-%06d.dcm", count); - printf(">> %s\n", buf); - Orthanc::SystemToolbox::WriteFile(t, buf); - } - - Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size()); - printf(" => transcoded transfer syntax %d ; %lu bytes\n", transcoder2.GetTransferSyntax(), t.size()); - } - } - - printf("\n"); -} - -TEST(Toto, DISABLED_Transcode) -{ - //OFLog::configure(OFLogger::DEBUG_LOG_LEVEL); - - if (1) - { - const char* const PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes"; - - for (boost::filesystem::directory_iterator it(PATH); - it != boost::filesystem::directory_iterator(); ++it) - { - if (boost::filesystem::is_regular_file(it->status())) - { - TestFile(it->path().string()); - } - } - } - - if (0) - { - TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Multiframe.dcm"); - TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Issue44/Monochrome1-Jpeg.dcm"); - } - - if (0) - { - TestFile("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/1.2.840.10008.1.2.1.dcm"); - } -} - - -TEST(Toto, DISABLED_Transcode2) -{ - for (int i = 0; i <= DicomTransferSyntax_XML; i++) - { - DicomTransferSyntax a = (DicomTransferSyntax) i; - - std::string path = ("/home/jodogne/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); - - DcmtkImageReader reader; - - { - std::unique_ptr<IParsedDicomImage> image( - reader.Read(source.c_str(), source.size())); - ASSERT_TRUE(image.get() != NULL); - ASSERT_EQ(a, image->GetTransferSyntax()); - - std::string target; - image->WriteToMemoryBuffer(target); - } - - for (int j = 0; j <= DicomTransferSyntax_XML; j++) - { - DicomTransferSyntax b = (DicomTransferSyntax) j; - //if (a == b) continue; - - std::unique_ptr<IParsedDicomImage> image( - reader.Transcode(source.c_str(), source.size(), b, true)); - if (image.get() != NULL) - { - printf("[%s] -> [%s]\n", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b)); - - std::string target; - image->WriteToMemoryBuffer(target); - - char buf[1024]; - sprintf(buf, "/tmp/%s-%s.dcm", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b)); - - SystemToolbox::WriteFile(target, buf); - } - else if (a != DicomTransferSyntax_JPEG2000 && - a != DicomTransferSyntax_JPEG2000LosslessOnly) - { - ASSERT_TRUE(b != DicomTransferSyntax_LittleEndianImplicit && - b != DicomTransferSyntax_LittleEndianExplicit && - b != DicomTransferSyntax_BigEndianExplicit && - b != DicomTransferSyntax_DeflatedLittleEndianExplicit); - } - } - } - } -} - - -#include "../Core/DicomNetworking/DicomAssociation.h" -#include "../Core/DicomNetworking/DicomControlUserConnection.h" -#include "../Core/DicomNetworking/DicomStoreUserConnection.h" - -TEST(Toto, DISABLED_DicomAssociation) -{ - DicomAssociationParameters params; - params.SetLocalApplicationEntityTitle("ORTHANC"); - params.SetRemoteApplicationEntityTitle("PACS"); - params.SetRemotePort(2001); - -#if 0 - DicomAssociation assoc; - assoc.ProposeGenericPresentationContext(UID_StorageCommitmentPushModelSOPClass); - assoc.ProposeGenericPresentationContext(UID_VerificationSOPClass); - assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, - DicomTransferSyntax_JPEGProcess1); - assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, - DicomTransferSyntax_JPEGProcess2_4); - assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage, - DicomTransferSyntax_JPEG2000); - - assoc.Open(params); - - int presID = ASC_findAcceptedPresentationContextID(&assoc.GetDcmtkAssociation(), UID_ComputedRadiographyImageStorage); - printf(">> %d\n", presID); - - std::map<DicomTransferSyntax, uint8_t> pc; - printf(">> %d\n", assoc.LookupAcceptedPresentationContext(pc, UID_ComputedRadiographyImageStorage)); - - for (std::map<DicomTransferSyntax, uint8_t>::const_iterator - it = pc.begin(); it != pc.end(); ++it) - { - printf("[%s] => %d\n", GetTransferSyntaxUid(it->first), it->second); - } -#else - { - DicomControlUserConnection assoc(params); - - try - { - printf(">> %d\n", assoc.Echo()); - } - catch (OrthancException&) - { - } - } - - params.SetRemoteApplicationEntityTitle("PACS"); - params.SetRemotePort(2000); - - { - DicomControlUserConnection assoc(params); - printf(">> %d\n", assoc.Echo()); - } - -#endif -} - -static void TestTranscode(DicomStoreUserConnection& scu, - const std::string& sopClassUid, - DicomTransferSyntax transferSyntax) -{ - std::set<DicomTransferSyntax> accepted; - - scu.LookupTranscoding(accepted, sopClassUid, transferSyntax); - if (accepted.empty()) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "The SOP class is not supported by the remote modality"); - } - - { - unsigned int count = 0; - for (std::set<DicomTransferSyntax>::const_iterator - it = accepted.begin(); it != accepted.end(); ++it) - { - LOG(INFO) << "available for transcoding " << (count++) << ": " << sopClassUid - << " / " << GetTransferSyntaxUid(*it); - } - } - - if (accepted.find(transferSyntax) != accepted.end()) - { - printf("**** OK, without transcoding !! [%s]\n", GetTransferSyntaxUid(transferSyntax)); - } - else - { - // Transcoding - only in Orthanc >= 1.7.0 - - const DicomTransferSyntax uncompressed[] = { - DicomTransferSyntax_LittleEndianImplicit, // Default transfer syntax - DicomTransferSyntax_LittleEndianExplicit, - DicomTransferSyntax_BigEndianExplicit - }; - - bool found = false; - for (size_t i = 0; i < 3; i++) - { - if (accepted.find(uncompressed[i]) != accepted.end()) - { - printf("**** TRANSCODING to %s\n", GetTransferSyntaxUid(uncompressed[i])); - found = true; - break; - } - } - - if (!found) - { - printf("**** KO KO KO\n"); - } - } -} - - -TEST(Toto, DISABLED_Store) -{ - DicomAssociationParameters params; - params.SetLocalApplicationEntityTitle("ORTHANC"); - params.SetRemoteApplicationEntityTitle("STORESCP"); - params.SetRemotePort(2000); - - DicomStoreUserConnection assoc(params); - assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess1); - assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess2_4); - //assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit); - - //assoc.SetUncompressedSyntaxesProposed(false); // Necessary for transcoding - assoc.SetCommonClassesProposed(false); - assoc.SetRetiredBigEndianProposed(true); - TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit); - TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000); - TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000); -} - - -TEST(Toto, DISABLED_Store2) -{ - DicomAssociationParameters params; - params.SetLocalApplicationEntityTitle("ORTHANC"); - params.SetRemoteApplicationEntityTitle("STORESCP"); - params.SetRemotePort(2000); - - DicomStoreUserConnection assoc(params); - //assoc.SetCommonClassesProposed(false); - assoc.SetRetiredBigEndianProposed(true); - - std::string s; - Orthanc::SystemToolbox::ReadFile(s, "/tmp/i/" + std::string(GetTransferSyntaxUid(DicomTransferSyntax_BigEndianExplicit)) +".dcm"); - - std::string c, i; - assoc.Store(c, i, s.c_str(), s.size()); - printf("[%s] [%s]\n", c.c_str(), i.c_str()); -} -
--- a/OrthancFramework/Resources/Patches/OpenSSL-ConfigureHeaders.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Patches/OpenSSL-ConfigureHeaders.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Patches/OpenSSL-ExtractProvidersOIDs.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Patches/OpenSSL-ExtractProvidersOIDs.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/boost-1.86.0-emscripten.patch Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,127 @@ +diff -urEb boost_1_86_0.orig/libs/locale/src/boost/locale/shared/date_time.cpp boost_1_86_0/libs/locale/src/boost/locale/shared/date_time.cpp +--- boost_1_86_0.orig/libs/locale/src/boost/locale/shared/date_time.cpp 2024-09-25 15:46:01.000000000 +0200 ++++ boost_1_86_0/libs/locale/src/boost/locale/shared/date_time.cpp 2024-09-25 15:58:51.306131987 +0200 +@@ -12,8 +12,10 @@ + #include <boost/locale/date_time.hpp> + #include <boost/locale/formatting.hpp> + #include <boost/core/exchange.hpp> +-#include <boost/thread/locks.hpp> +-#include <boost/thread/mutex.hpp> ++#if !defined(__EMSCRIPTEN__) ++# include <boost/thread/locks.hpp> ++# include <boost/thread/mutex.hpp> ++#endif + #include <cmath> + + 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,7 +425,7 @@ + return boost::exchange(tz_id(), new_id); + } + } // namespace time_zone +- ++#endif + }} // namespace boost::locale + + // boostinspect:nominmax +diff -urEb boost_1_86_0.orig/libs/locale/src/boost/locale/shared/generator.cpp boost_1_86_0/libs/locale/src/boost/locale/shared/generator.cpp +--- boost_1_86_0.orig/libs/locale/src/boost/locale/shared/generator.cpp 2024-09-25 15:46:01.000000000 +0200 ++++ boost_1_86_0/libs/locale/src/boost/locale/shared/generator.cpp 2024-09-25 16:00:07.756233916 +0200 +@@ -7,8 +7,10 @@ + #include <boost/locale/encoding.hpp> + #include <boost/locale/generator.hpp> + #include <boost/locale/localization_backend.hpp> +-#include <boost/thread/locks.hpp> +-#include <boost/thread/mutex.hpp> ++#if !defined(__EMSCRIPTEN__) ++# include <boost/thread/locks.hpp> ++# include <boost/thread/mutex.hpp> ++#endif + #include <algorithm> + #include <map> + #include <vector> +@@ -21,8 +23,9 @@ + {} + + mutable std::map<std::string, std::locale> cached; ++#if !defined(__EMSCRIPTEN__) + mutable boost::mutex cached_lock; +- ++#endif + category_t cats; + char_facet_t chars; + +@@ -101,7 +104,9 @@ + std::locale generator::generate(const std::locale& base, const std::string& id) const + { + if(d->caching_enabled) { ++#if !defined(__EMSCRIPTEN__) + boost::unique_lock<boost::mutex> guard(d->cached_lock); ++#endif + const auto p = d->cached.find(id); + if(p != d->cached.end()) + return p->second; +@@ -126,7 +131,9 @@ + result = backend->install(result, facet, char_facet_t::nochar); + } + if(d->caching_enabled) { ++#if !defined(__EMSCRIPTEN__) + boost::unique_lock<boost::mutex> 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_86_0.orig/libs/locale/src/boost/locale/shared/localization_backend.cpp boost_1_86_0/libs/locale/src/boost/locale/shared/localization_backend.cpp +--- boost_1_86_0.orig/libs/locale/src/boost/locale/shared/localization_backend.cpp 2024-09-25 15:46:01.000000000 +0200 ++++ boost_1_86_0/libs/locale/src/boost/locale/shared/localization_backend.cpp 2024-09-25 16:01:09.196820495 +0200 +@@ -5,8 +5,10 @@ + // https://www.boost.org/LICENSE_1_0.txt + + #include <boost/locale/localization_backend.hpp> +-#include <boost/thread/locks.hpp> +-#include <boost/thread/mutex.hpp> ++#if !defined(__EMSCRIPTEN__) ++# include <boost/thread/locks.hpp> ++# include <boost/thread/mutex.hpp> ++#endif + #include <functional> + #include <memory> + #include <vector> +@@ -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<boost::mutex> 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<boost::mutex> lock(localization_backend_manager_mutex()); ++#endif + return exchange(localization_backend_manager_global(), in); + } +
--- a/OrthancFramework/Resources/Patches/dcmtk-3.6.8.patch Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Patches/dcmtk-3.6.8.patch Thu Jan 30 17:41:33 2025 +0100 @@ -1,6 +1,6 @@ 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 +--- dcmtk-DCMTK-3.6.8.orig/CMake/GenerateDCMTKConfigure.cmake 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/CMake/GenerateDCMTKConfigure.cmake 2024-11-25 16:54:59.036009112 +0100 @@ -224,6 +224,8 @@ # Check the sizes of various types @@ -18,9 +18,11 @@ # Check for include files, libraries, and functions include("${DCMTK_CMAKE_INCLUDE}CMake/dcmtkTryCompile.cmake") +Only in dcmtk-DCMTK-3.6.8/config/include/dcmtk/config: arith.h +Only in dcmtk-DCMTK-3.6.8/config/include/dcmtk/config: osconfig.h 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 +--- dcmtk-DCMTK-3.6.8.orig/dcmdata/include/dcmtk/dcmdata/dcdict.h 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmdata/include/dcmtk/dcmdata/dcdict.h 2024-11-25 16:54:59.036009112 +0100 @@ -162,6 +162,12 @@ /// returns an iterator to the end of the repeating tag dictionary DcmDictEntryListIterator repeatingEnd() { return repDict.end(); } @@ -35,17 +37,18 @@ /** 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 +--- dcmtk-DCMTK-3.6.8.orig/dcmdata/libsrc/dcdict.cc 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmdata/libsrc/dcdict.cc 2024-11-25 16:54:59.036009112 +0100 @@ -914,3 +914,5 @@ wrlock().clear(); wrunlock(); } + +#include "dcdict_orthanc.cc" +Only in dcmtk-DCMTK-3.6.8/dcmdata/libsrc: 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 +--- dcmtk-DCMTK-3.6.8.orig/dcmdata/libsrc/dcpxitem.cc 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmdata/libsrc/dcpxitem.cc 2024-11-25 16:54:59.036009112 +0100 @@ -31,6 +31,9 @@ #include "dcmtk/dcmdata/dcostrma.h" /* for class DcmOutputStream */ #include "dcmtk/dcmdata/dcwcache.h" /* for class DcmWriteCache */ @@ -57,8 +60,8 @@ // ******************************** 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 +--- dcmtk-DCMTK-3.6.8.orig/dcmnet/libsrc/scu.cc 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmnet/libsrc/scu.cc 2024-11-25 16:54:59.036009112 +0100 @@ -19,6 +19,11 @@ * */ @@ -72,8 +75,8 @@ #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 +--- dcmtk-DCMTK-3.6.8.orig/oflog/include/dcmtk/oflog/thread/syncpub.h 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/oflog/include/dcmtk/oflog/thread/syncpub.h 2024-11-25 16:54:59.037009100 +0100 @@ -63,7 +63,7 @@ DCMTK_LOG4CPLUS_INLINE_EXPORT @@ -111,8 +114,8 @@ 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 +--- dcmtk-DCMTK-3.6.8.orig/oflog/libsrc/oflog.cc 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/oflog/libsrc/oflog.cc 2024-11-25 16:54:59.037009100 +0100 @@ -19,6 +19,11 @@ * */ @@ -126,8 +129,8 @@ #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 +--- dcmtk-DCMTK-3.6.8.orig/ofstd/include/dcmtk/ofstd/offile.h 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/ofstd/include/dcmtk/ofstd/offile.h 2024-11-25 16:54:59.037009100 +0100 @@ -570,7 +570,7 @@ */ void setlinebuf() @@ -137,3 +140,18 @@ this->setvbuf(NULL, _IOLBF, 0); #else :: setlinebuf(file_); +diff -urEb dcmtk-DCMTK-3.6.8.orig/ofstd/include/dcmtk/ofstd/ofutil.h dcmtk-DCMTK-3.6.8/ofstd/include/dcmtk/ofstd/ofutil.h +--- dcmtk-DCMTK-3.6.8.orig/ofstd/include/dcmtk/ofstd/ofutil.h 2023-12-19 11:12:57.000000000 +0100 ++++ dcmtk-DCMTK-3.6.8/ofstd/include/dcmtk/ofstd/ofutil.h 2024-11-25 17:00:27.525244000 +0100 +@@ -75,8 +75,8 @@ + // copy constructor should be fine for primitive types. + inline type(const T& pt) + : t( pt ) {} +- inline type(const OFrvalue_storage& rhs) +- : t( rhs.pt ) {} ++ inline type(const type& rhs) ++ : t( rhs.t ) {} + + // automatic conversion to the underlying type + inline operator T&() const { return OFconst_cast( T&, t ); } +Only in dcmtk-DCMTK-3.6.8/ofstd/include/dcmtk/ofstd: ofutil.h~
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/dcmtk-3.6.9-visual-studio.patch Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,1615 @@ +diff -urEb dcmtk-3.6.9.orig/config/math.cc dcmtk-3.6.9/config/math.cc +--- dcmtk-3.6.9.orig/config/math.cc 2025-01-16 18:04:46.121846434 +0100 ++++ dcmtk-3.6.9/config/math.cc 2025-01-17 07:45:46.252026376 +0100 +@@ -42,11 +42,17 @@ + #include <windows.h> + #endif + ++#if defined(_MSC_VER) ++#include <float.h> ++#endif ++ + struct dcmtk_config_math + { + static inline OFBool isnan( float f ) + { +-#ifdef HAVE_PROTOTYPE_STD__ISNAN ++#if defined(_MSC_VER) ++ return _isnan(static_cast<double>(f)) != 0; ++#elif defined(HAVE_PROTOTYPE_STD__ISNAN) + return STD_NAMESPACE isnan(f); + #else + return ::isnan(f); +@@ -55,7 +61,9 @@ + + static inline OFBool isnan( double d ) + { +-#ifdef HAVE_PROTOTYPE_STD__ISNAN ++#if defined(_MSC_VER) ++ return _isnan(d) != 0; ++#elif defined(HAVE_PROTOTYPE_STD__ISNAN) + return STD_NAMESPACE isnan(d); + #else + return ::isnan(d); +@@ -64,7 +72,9 @@ + + static inline OFBool isinf( float f ) + { +-#ifdef HAVE_PROTOTYPE_STD__ISINF ++#if defined(_MSC_VER) ++ return _finite(static_cast<double>(f)) != 0; ++#elif defined(HAVE_PROTOTYPE_STD__ISINF) + return STD_NAMESPACE isinf( f ); + #else + return ::isinf( f ); +@@ -73,7 +83,9 @@ + + static inline OFBool isinf( double d ) + { +-#ifdef HAVE_PROTOTYPE_STD__ISINF ++#if defined(_MSC_VER) ++ return _finite(d) != 0; ++#elif defined(HAVE_PROTOTYPE_STD__ISINF) + return STD_NAMESPACE isinf( d ); + #else + return ::isinf( d ); +diff -urEb dcmtk-3.6.9.orig/dcmjpeg/libijg12/jccoefct.c dcmtk-3.6.9/dcmjpeg/libijg12/jccoefct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jccoefct.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jccoefct.c 2025-01-16 20:11:42.016717178 +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-3.6.9.orig/dcmjpeg/libijg12/jcdiffct.c dcmtk-3.6.9/dcmjpeg/libijg12/jcdiffct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jcdiffct.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jcdiffct.c 2025-01-16 20:11:42.016717178 +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-3.6.9.orig/dcmjpeg/libijg12/jcpred.c dcmtk-3.6.9/dcmjpeg/libijg12/jcpred.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jcpred.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jcpred.c 2025-01-16 20:11:42.017717169 +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-3.6.9.orig/dcmjpeg/libijg12/jctrans.c dcmtk-3.6.9/dcmjpeg/libijg12/jctrans.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jctrans.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jctrans.c 2025-01-16 20:11:42.017717169 +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-3.6.9.orig/dcmjpeg/libijg12/jdmerge.c dcmtk-3.6.9/dcmjpeg/libijg12/jdmerge.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jdmerge.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jdmerge.c 2025-01-16 20:11:42.017717169 +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-3.6.9.orig/dcmjpeg/libijg12/jdpostct.c dcmtk-3.6.9/dcmjpeg/libijg12/jdpostct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jdpostct.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jdpostct.c 2025-01-16 20:11:42.017717169 +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-3.6.9.orig/dcmjpeg/libijg12/jdpred.c dcmtk-3.6.9/dcmjpeg/libijg12/jdpred.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jdpred.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jdpred.c 2025-01-16 20:11:42.017717169 +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-3.6.9.orig/dcmjpeg/libijg12/jdsample.c dcmtk-3.6.9/dcmjpeg/libijg12/jdsample.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jdsample.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jdsample.c 2025-01-16 20:11:42.018717160 +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-3.6.9.orig/dcmjpeg/libijg12/jdscale.c dcmtk-3.6.9/dcmjpeg/libijg12/jdscale.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jdscale.c 2025-01-16 18:04:46.157846124 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jdscale.c 2025-01-16 20:11:42.018717160 +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-3.6.9.orig/dcmjpeg/libijg12/jerror.c dcmtk-3.6.9/dcmjpeg/libijg12/jerror.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jerror.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jerror.c 2025-01-17 11:14:11.975382089 +0100 +@@ -34,6 +34,10 @@ + #define EXIT_FAILURE 1 + #endif + ++#if defined(_MSC_VER) && _MSC_VER < 1900 ++#define snprintf _snprintf ++#endif ++ + + /* + * Create the message string table. +diff -urEb dcmtk-3.6.9.orig/dcmjpeg/libijg12/jquant1.c dcmtk-3.6.9/dcmjpeg/libijg12/jquant1.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jquant1.c 2025-01-16 18:04:46.157846124 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jquant1.c 2025-01-16 20:11:42.018717160 +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-3.6.9.orig/dcmjpeg/libijg12/jquant2.c dcmtk-3.6.9/dcmjpeg/libijg12/jquant2.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg12/jquant2.c 2025-01-16 18:04:46.157846124 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg12/jquant2.c 2025-01-16 20:11:42.018717160 +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-3.6.9.orig/dcmjpeg/libijg16/jccoefct.c dcmtk-3.6.9/dcmjpeg/libijg16/jccoefct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jccoefct.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jccoefct.c 2025-01-16 20:11:42.019717150 +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-3.6.9.orig/dcmjpeg/libijg16/jcdiffct.c dcmtk-3.6.9/dcmjpeg/libijg16/jcdiffct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jcdiffct.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jcdiffct.c 2025-01-16 20:11:42.019717150 +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-3.6.9.orig/dcmjpeg/libijg16/jcpred.c dcmtk-3.6.9/dcmjpeg/libijg16/jcpred.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jcpred.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jcpred.c 2025-01-16 20:11:42.019717150 +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-3.6.9.orig/dcmjpeg/libijg16/jctrans.c dcmtk-3.6.9/dcmjpeg/libijg16/jctrans.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jctrans.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jctrans.c 2025-01-16 20:11:42.019717150 +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-3.6.9.orig/dcmjpeg/libijg16/jdmerge.c dcmtk-3.6.9/dcmjpeg/libijg16/jdmerge.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jdmerge.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jdmerge.c 2025-01-16 20:11:42.019717150 +0100 +@@ -169,7 +169,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 */ +@@ -219,8 +219,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-3.6.9.orig/dcmjpeg/libijg16/jdpostct.c dcmtk-3.6.9/dcmjpeg/libijg16/jdpostct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jdpostct.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jdpostct.c 2025-01-16 20:11:42.019717150 +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-3.6.9.orig/dcmjpeg/libijg16/jdpred.c dcmtk-3.6.9/dcmjpeg/libijg16/jdpred.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jdpred.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jdpred.c 2025-01-16 20:11:42.020717140 +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-3.6.9.orig/dcmjpeg/libijg16/jdsample.c dcmtk-3.6.9/dcmjpeg/libijg16/jdsample.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jdsample.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jdsample.c 2025-01-16 20:11:42.020717140 +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-3.6.9.orig/dcmjpeg/libijg16/jdscale.c dcmtk-3.6.9/dcmjpeg/libijg16/jdscale.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jdscale.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jdscale.c 2025-01-16 20:11:42.020717140 +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-3.6.9.orig/dcmjpeg/libijg16/jerror.c dcmtk-3.6.9/dcmjpeg/libijg16/jerror.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jerror.c 2025-01-16 18:04:46.159846107 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jerror.c 2025-01-17 11:14:19.002328399 +0100 +@@ -34,6 +34,10 @@ + #define EXIT_FAILURE 1 + #endif + ++#if defined(_MSC_VER) && _MSC_VER < 1900 ++#define snprintf _snprintf ++#endif ++ + + /* + * Create the message string table. +diff -urEb dcmtk-3.6.9.orig/dcmjpeg/libijg16/jquant1.c dcmtk-3.6.9/dcmjpeg/libijg16/jquant1.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jquant1.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jquant1.c 2025-01-16 20:11:42.020717140 +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-3.6.9.orig/dcmjpeg/libijg16/jquant2.c dcmtk-3.6.9/dcmjpeg/libijg16/jquant2.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg16/jquant2.c 2025-01-16 18:04:46.158846116 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg16/jquant2.c 2025-01-16 20:11:42.021717131 +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-3.6.9.orig/dcmjpeg/libijg8/jccoefct.c dcmtk-3.6.9/dcmjpeg/libijg8/jccoefct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jccoefct.c 2025-01-16 18:04:46.161846090 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jccoefct.c 2025-01-16 20:11:42.021717131 +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-3.6.9.orig/dcmjpeg/libijg8/jcdiffct.c dcmtk-3.6.9/dcmjpeg/libijg8/jcdiffct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jcdiffct.c 2025-01-16 18:04:46.161846090 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jcdiffct.c 2025-01-16 20:11:42.021717131 +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-3.6.9.orig/dcmjpeg/libijg8/jcpred.c dcmtk-3.6.9/dcmjpeg/libijg8/jcpred.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jcpred.c 2025-01-16 18:04:46.161846090 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jcpred.c 2025-01-16 20:11:42.021717131 +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-3.6.9.orig/dcmjpeg/libijg8/jctrans.c dcmtk-3.6.9/dcmjpeg/libijg8/jctrans.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jctrans.c 2025-01-16 18:04:46.161846090 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jctrans.c 2025-01-16 20:11:42.021717131 +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-3.6.9.orig/dcmjpeg/libijg8/jdmerge.c dcmtk-3.6.9/dcmjpeg/libijg8/jdmerge.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jdmerge.c 2025-01-16 18:04:46.161846090 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jdmerge.c 2025-01-16 20:11:42.021717131 +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-3.6.9.orig/dcmjpeg/libijg8/jdpostct.c dcmtk-3.6.9/dcmjpeg/libijg8/jdpostct.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jdpostct.c 2025-01-16 18:04:46.160846099 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jdpostct.c 2025-01-16 20:11:42.022717122 +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-3.6.9.orig/dcmjpeg/libijg8/jdpred.c dcmtk-3.6.9/dcmjpeg/libijg8/jdpred.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jdpred.c 2025-01-16 18:04:46.161846090 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jdpred.c 2025-01-16 20:11:42.022717122 +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-3.6.9.orig/dcmjpeg/libijg8/jdsample.c dcmtk-3.6.9/dcmjpeg/libijg8/jdsample.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jdsample.c 2025-01-16 18:04:46.161846090 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jdsample.c 2025-01-16 20:11:42.022717122 +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-3.6.9.orig/dcmjpeg/libijg8/jdscale.c dcmtk-3.6.9/dcmjpeg/libijg8/jdscale.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jdscale.c 2025-01-16 18:04:46.160846099 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jdscale.c 2025-01-16 20:11:42.022717122 +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-3.6.9.orig/dcmjpeg/libijg8/jerror.c dcmtk-3.6.9/dcmjpeg/libijg8/jerror.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jerror.c 2025-01-16 18:04:46.160846099 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jerror.c 2025-01-17 11:14:02.543454148 +0100 +@@ -34,6 +34,10 @@ + #define EXIT_FAILURE 1 + #endif + ++#if defined(_MSC_VER) && _MSC_VER < 1900 ++#define snprintf _snprintf ++#endif ++ + + /* + * Create the message string table. +diff -urEb dcmtk-3.6.9.orig/dcmjpeg/libijg8/jquant1.c dcmtk-3.6.9/dcmjpeg/libijg8/jquant1.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jquant1.c 2025-01-16 18:04:46.160846099 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jquant1.c 2025-01-16 20:11:42.022717122 +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-3.6.9.orig/dcmjpeg/libijg8/jquant2.c dcmtk-3.6.9/dcmjpeg/libijg8/jquant2.c +--- dcmtk-3.6.9.orig/dcmjpeg/libijg8/jquant2.c 2025-01-16 18:04:46.160846099 +0100 ++++ dcmtk-3.6.9/dcmjpeg/libijg8/jquant2.c 2025-01-16 20:11:42.023717112 +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-3.6.9.orig/oficonv/libsrc/citrus_bcs.h dcmtk-3.6.9/oficonv/libsrc/citrus_bcs.h +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_bcs.h 2025-01-16 18:04:46.146846219 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_bcs.h 2025-01-17 11:14:44.746131630 +0100 +@@ -39,7 +39,21 @@ + #include <errno.h> + #include <stdint.h> + #include <limits.h> ++ ++#undef EOPNOTSUPP ++#define EOPNOTSUPP 130 // https://learn.microsoft.com/fr-fr/cpp/c-runtime-library/errno-constants ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ ++#if defined(_MSC_VER) && _MSC_VER < 1900 ++#define snprintf _snprintf ++#endif + + #define CITRUS_DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) + +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_big5.c dcmtk-3.6.9/oficonv/libsrc/citrus_big5.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_big5.c 2025-01-16 18:04:46.137846297 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_big5.c 2025-01-17 09:59:15.249381150 +0100 +@@ -218,13 +218,6 @@ + return (0); + } + +-static const _citrus_prop_hint_t root_hints[] = { +- _CITRUS_PROP_HINT_NUM("row", &_citrus_BIG5_fill_rowcol), +- _CITRUS_PROP_HINT_NUM("col", &_citrus_BIG5_fill_rowcol), +- _CITRUS_PROP_HINT_NUM("excludes", &_citrus_BIG5_fill_excludes), +- _CITRUS_PROP_HINT_END +-}; +- + static void + /*ARGSUSED*/ + _citrus_BIG5_encoding_module_uninit(_BIG5EncodingInfo *ei) +@@ -245,6 +238,18 @@ + const char *s; + int err; + ++ _citrus_prop_hint_t root_hints[4]; ++ root_hints[0].name = "row"; ++ root_hints[0].type = _CITRUS_PROP_NUM; ++ root_hints[0].cb.num.func = _citrus_BIG5_fill_rowcol; ++ root_hints[1].name = "col"; ++ root_hints[1].type = _CITRUS_PROP_NUM; ++ root_hints[1].cb.num.func = _citrus_BIG5_fill_rowcol; ++ root_hints[2].name = "excludes"; ++ root_hints[2].type = _CITRUS_PROP_NUM; ++ root_hints[2].cb.num.func = _citrus_BIG5_fill_excludes; ++ root_hints[3].name = NULL; // _CITRUS_PROP_HINT_END ++ + memset((void *)ei, 0, sizeof(*ei)); + TAILQ_INIT(&ei->excludes); + +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_db_hash.h dcmtk-3.6.9/oficonv/libsrc/citrus_db_hash.h +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_db_hash.h 2025-01-16 18:04:46.135846314 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_db_hash.h 2025-01-17 09:36:14.692449741 +0100 +@@ -29,7 +29,8 @@ + + #include "dcmtk/config/osconfig.h" + #include "dcmtk/oficonv/oidefine.h" +-#include <inttypes.h> ++ ++#include <stdint.h> + + struct _citrus_region; + +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_esdb.c dcmtk-3.6.9/oficonv/libsrc/citrus_esdb.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_esdb.c 2025-01-16 18:04:46.137846297 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_esdb.c 2025-01-17 07:57:57.711032732 +0100 +@@ -34,7 +34,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stdio.h> + #include <stdlib.h> + #include <string.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_esdb.h dcmtk-3.6.9/oficonv/libsrc/citrus_esdb.h +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_esdb.h 2025-01-16 18:04:46.137846297 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_esdb.h 2025-01-17 07:58:02.525992089 +0100 +@@ -29,7 +29,14 @@ + + #include "dcmtk/config/osconfig.h" + #include "citrus_types.h" ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif + + struct _citrus_esdb_charset { + _citrus_csid_t ec_csid; +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_gbk2k.c dcmtk-3.6.9/oficonv/libsrc/citrus_gbk2k.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_gbk2k.c 2025-01-16 18:04:46.146846219 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_gbk2k.c 2025-01-17 07:58:08.702939916 +0100 +@@ -34,7 +34,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stddef.h> + #include <stdio.h> + #include <stdlib.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_hz.c dcmtk-3.6.9/oficonv/libsrc/citrus_hz.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_hz.c 2025-01-16 18:04:46.144846236 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_hz.c 2025-01-17 10:04:16.511792074 +0100 +@@ -571,13 +571,6 @@ + return (0); + } + +-static const _citrus_prop_hint_t escape_hints[] = { +-_CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char), +-_CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic), +-_CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic), +-_CITRUS_PROP_HINT_END +-}; +- + static int + _citrus_HZ_parse_escape(void *context, const char *name, const char *s) + { +@@ -585,6 +578,18 @@ + escape_t *escape; + void *p[2]; + ++ _citrus_prop_hint_t escape_hints[4]; ++ escape_hints[0].name = "CH"; ++ escape_hints[0].type = _CITRUS_PROP_STR; ++ escape_hints[0].cb.str.func = _citrus_HZ_parse_char; ++ escape_hints[1].name = "GL"; ++ escape_hints[1].type = _CITRUS_PROP_STR; ++ escape_hints[1].cb.str.func = _citrus_HZ_parse_graphic; ++ escape_hints[2].name = "GR"; ++ escape_hints[2].type = _CITRUS_PROP_STR; ++ escape_hints[2].cb.str.func = _citrus_HZ_parse_graphic; ++ escape_hints[3].name = NULL; // _CITRUS_PROP_HINT_END ++ + ei = (_HZEncodingInfo *)context; + escape = calloc(1, sizeof(*escape)); + if (escape == NULL) +@@ -605,18 +610,21 @@ + escape_hints, (void *)&p[0], s, strlen(s))); + } + +-static const _citrus_prop_hint_t root_hints[] = { +-_CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape), +-_CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape), +-_CITRUS_PROP_HINT_END +-}; +- + static int + _citrus_HZ_encoding_module_init(_HZEncodingInfo * ei, + const void * var, size_t lenvar) + { + int errnum; + ++ _citrus_prop_hint_t root_hints[3]; ++ root_hints[0].name = "0"; ++ root_hints[0].type = _CITRUS_PROP_STR; ++ root_hints[0].cb.str.func = _citrus_HZ_parse_escape; ++ root_hints[1].name = "1"; ++ root_hints[1].type = _CITRUS_PROP_STR; ++ root_hints[1].cb.str.func = _citrus_HZ_parse_escape; ++ root_hints[2].name = NULL; // _CITRUS_PROP_HINT_END ++ + memset(ei, 0, sizeof(*ei)); + TAILQ_INIT(E0SET(ei)); + TAILQ_INIT(E1SET(ei)); +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv.c dcmtk-3.6.9/oficonv/libsrc/citrus_iconv.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv.c 2025-01-16 18:04:46.146846219 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_iconv.c 2025-01-17 09:23:11.596327937 +0100 +@@ -49,7 +49,15 @@ + #endif + + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stdio.h> + #include <stdlib.h> + #include <string.h> +@@ -299,14 +307,17 @@ + _citrus_iconv_open(struct _citrus_iconv * * rcv, + const char * src, const char * dst) + { +-struct _citrus_iconv *cv = NULL; ++#ifdef HAVE_WINDOWS_H ++ char current_codepage[20]; ++#endif ++ ++ struct _citrus_iconv *cv = NULL; + struct _citrus_iconv_shared *ci = NULL; + char realdst[OFICONV_PATH_MAX], realsrc[OFICONV_PATH_MAX]; + int ret; + + init_cache(); + #ifdef HAVE_WINDOWS_H +- char current_codepage[20]; + snprintf(current_codepage, sizeof(current_codepage), "%lu", (unsigned long) GetConsoleOutputCP()); + #endif + +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv_local.h dcmtk-3.6.9/oficonv/libsrc/citrus_iconv_local.h +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv_local.h 2025-01-16 18:04:46.146846219 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_iconv_local.h 2025-01-17 07:58:20.317841727 +0100 +@@ -29,7 +29,15 @@ + + #include "dcmtk/config/osconfig.h" + #include "dcmtk/oficonv/iconv.h" ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stdint.h> + + #ifdef HAVE_SYS_QUEUE_H +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv_none.c dcmtk-3.6.9/oficonv/libsrc/citrus_iconv_none.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv_none.c 2025-01-16 18:04:46.141846262 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_iconv_none.c 2025-01-17 07:58:25.509797800 +0100 +@@ -35,7 +35,15 @@ + + + #include <errno.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stdlib.h> + #include <string.h> + +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv_std.c dcmtk-3.6.9/oficonv/libsrc/citrus_iconv_std.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iconv_std.c 2025-01-16 18:04:46.141846262 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_iconv_std.c 2025-01-17 07:58:30.205758052 +0100 +@@ -36,7 +36,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stdio.h> + #include <stdlib.h> + #include <string.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iso2022.c dcmtk-3.6.9/oficonv/libsrc/citrus_iso2022.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_iso2022.c 2025-01-16 18:04:46.142846254 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_iso2022.c 2025-01-17 07:58:35.485713336 +0100 +@@ -35,7 +35,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stddef.h> + #include <stdio.h> + #include <stdlib.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_johab.c dcmtk-3.6.9/oficonv/libsrc/citrus_johab.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_johab.c 2025-01-16 18:04:46.144846236 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_johab.c 2025-01-17 07:58:40.390671776 +0100 +@@ -34,7 +34,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stddef.h> + #include <stdint.h> + #include <stdio.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_module.c dcmtk-3.6.9/oficonv/libsrc/citrus_module.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_module.c 2025-01-16 18:04:46.146846219 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_module.c 2025-01-17 07:58:45.172631238 +0100 +@@ -98,7 +98,15 @@ + #endif + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stddef.h> + #include <stdio.h> + #include <stdlib.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_mskanji.c dcmtk-3.6.9/oficonv/libsrc/citrus_mskanji.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_mskanji.c 2025-01-16 18:04:46.146846219 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_mskanji.c 2025-01-17 07:58:51.749575452 +0100 +@@ -67,7 +67,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stddef.h> + #include <stdio.h> + #include <stdlib.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_prop.c dcmtk-3.6.9/oficonv/libsrc/citrus_prop.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_prop.c 2025-01-16 18:04:46.140846271 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_prop.c 2025-01-17 07:58:55.534543331 +0100 +@@ -30,7 +30,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stdio.h> + #include <stdlib.h> + #include <string.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_region.h dcmtk-3.6.9/oficonv/libsrc/citrus_region.h +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_region.h 2025-01-16 18:04:46.142846254 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_region.h 2025-01-17 07:59:02.917480641 +0100 +@@ -31,7 +31,14 @@ + #include "dcmtk/config/osconfig.h" + #include <stdint.h> + #include <string.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif + + #ifdef HAVE_SYS_TYPES_H + #include <sys/types.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_utf8.c dcmtk-3.6.9/oficonv/libsrc/citrus_utf8.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_utf8.c 2025-01-16 18:04:46.146846219 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_utf8.c 2025-01-17 07:57:46.519127132 +0100 +@@ -66,7 +66,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stddef.h> + #include <stdio.h> + #include <stdlib.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/oficonv_iconv.c dcmtk-3.6.9/oficonv/libsrc/oficonv_iconv.c +--- dcmtk-3.6.9.orig/oficonv/libsrc/oficonv_iconv.c 2025-01-16 18:04:46.137846297 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/oficonv_iconv.c 2025-01-17 09:16:42.622548106 +0100 +@@ -40,7 +40,15 @@ + + #include <errno.h> + #include <limits.h> ++ ++#if (_MSC_VER >= 1900) + #include <stdbool.h> ++#else ++#define bool int ++#define false 0 ++#define true 1 ++#endif ++ + #include <stdlib.h> + #include <string.h> + #include <stdio.h> +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/windows_mmap.h dcmtk-3.6.9/oficonv/libsrc/windows_mmap.h +--- dcmtk-3.6.9.orig/oficonv/libsrc/windows_mmap.h 2025-01-16 18:04:46.137846297 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/windows_mmap.h 2025-01-17 09:21:53.565976060 +0100 +@@ -74,6 +74,12 @@ + + static void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) + { ++ DWORD flProtect; ++ DWORD dwDesiredAccess; ++ HANDLE mmap_fd, h; ++ off_t end; ++ void *ret; ++ + (void) start; + + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) +@@ -84,7 +90,6 @@ + } else if (flags & MAP_ANON) + return MAP_FAILED; + +- DWORD flProtect; + flProtect = 0; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) +@@ -99,8 +104,7 @@ + } else + flProtect = PAGE_READONLY; + +- off_t end = (off_t)(length + offset); +- HANDLE mmap_fd, h; ++ end = (off_t)(length + offset); + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else +@@ -109,7 +113,6 @@ + if (h == NULL) + return MAP_FAILED; + +- DWORD dwDesiredAccess; + if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else +@@ -118,7 +121,7 @@ + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; +- void *ret = MapViewOfFile(h, dwDesiredAccess, MM_DWORD_HI(offset), MM_DWORD_LO(offset), length); ++ ret = MapViewOfFile(h, dwDesiredAccess, MM_DWORD_HI(offset), MM_DWORD_LO(offset), length); + if (ret == NULL) { + CloseHandle(h); + ret = MAP_FAILED; +@@ -140,11 +143,13 @@ + + static void munmap(void *addr, size_t length) + { ++ mmap_cleanup_t **prevPtr; ++ mmap_cleanup_t *mc; ++ + (void) length; + UnmapViewOfFile(addr); + // Look up through the tracking elements to close the handle +- mmap_cleanup_t **prevPtr = &mmap_cleanup; +- mmap_cleanup_t *mc; ++ prevPtr = &mmap_cleanup; + for (mc = *prevPtr; mc != NULL; prevPtr = &mc->next, mc = *prevPtr) + { + if (mc->addr == addr) +diff -urEb dcmtk-3.6.9.orig/ofstd/include/dcmtk/ofstd/oftypes.h dcmtk-3.6.9/ofstd/include/dcmtk/ofstd/oftypes.h +--- dcmtk-3.6.9.orig/ofstd/include/dcmtk/ofstd/oftypes.h 2025-01-16 18:04:46.148846202 +0100 ++++ dcmtk-3.6.9/ofstd/include/dcmtk/ofstd/oftypes.h 2025-01-17 07:49:26.122182761 +0100 +@@ -79,10 +79,9 @@ + + #include <cstddef> + BEGIN_EXTERN_C +-#ifdef HAVE_STDINT_H ++#if defined(HAVE_STDINT_H) || _MSC_VER >= 1600 + #include <stdint.h> + #endif +-#include <inttypes.h> + END_EXTERN_C + + #include "dcmtk/ofstd/ofstream.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/dcmtk-3.6.9.patch Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,179 @@ +diff -urEb dcmtk-3.6.9.orig/CMake/GenerateDCMTKConfigure.cmake dcmtk-3.6.9/CMake/GenerateDCMTKConfigure.cmake +--- dcmtk-3.6.9.orig/CMake/GenerateDCMTKConfigure.cmake 2025-01-21 15:53:12.632715225 +0100 ++++ dcmtk-3.6.9/CMake/GenerateDCMTKConfigure.cmake 2025-01-21 15:53:27.614627545 +0100 +@@ -227,12 +227,15 @@ + + # 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("double" SIZEOF_DOUBLE) + CHECK_TYPE_SIZE("float" SIZEOF_FLOAT) + CHECK_TYPE_SIZE("int" SIZEOF_INT) + 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-3.6.9.orig/dcmdata/include/dcmtk/dcmdata/dcdict.h dcmtk-3.6.9/dcmdata/include/dcmtk/dcmdata/dcdict.h +--- dcmtk-3.6.9.orig/dcmdata/include/dcmtk/dcmdata/dcdict.h 2025-01-21 15:53:12.622715283 +0100 ++++ dcmtk-3.6.9/dcmdata/include/dcmtk/dcmdata/dcdict.h 2025-01-21 15:53:27.614627545 +0100 +@@ -163,6 +163,12 @@ + /// returns an iterator to the end of the repeating groups data 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-3.6.9.orig/dcmdata/libsrc/dcdict.cc dcmtk-3.6.9/dcmdata/libsrc/dcdict.cc +--- dcmtk-3.6.9.orig/dcmdata/libsrc/dcdict.cc 2025-01-21 15:53:12.625715265 +0100 ++++ dcmtk-3.6.9/dcmdata/libsrc/dcdict.cc 2025-01-21 15:53:27.615627539 +0100 +@@ -904,3 +904,5 @@ + wrlock().clear(); + wrunlock(); + } ++ ++#include "dcdict_orthanc.cc" +diff -urEb dcmtk-3.6.9.orig/dcmdata/libsrc/dcpxitem.cc dcmtk-3.6.9/dcmdata/libsrc/dcpxitem.cc +--- dcmtk-3.6.9.orig/dcmdata/libsrc/dcpxitem.cc 2025-01-21 15:53:12.623715277 +0100 ++++ dcmtk-3.6.9/dcmdata/libsrc/dcpxitem.cc 2025-01-21 15:53:27.615627539 +0100 +@@ -31,6 +31,8 @@ + #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-3.6.9.orig/dcmnet/libsrc/scu.cc dcmtk-3.6.9/dcmnet/libsrc/scu.cc +--- dcmtk-3.6.9.orig/dcmnet/libsrc/scu.cc 2025-01-21 15:53:12.655715091 +0100 ++++ dcmtk-3.6.9/dcmnet/libsrc/scu.cc 2025-01-21 15:53:27.616627533 +0100 +@@ -19,6 +19,11 @@ + * + */ + ++#if defined(_WIN32) ++# define __STDC_LIMIT_MACROS // Get access to UINT16_MAX ++# include <stdint.h> ++#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-3.6.9.orig/oficonv/include/dcmtk/oficonv/iconv.h dcmtk-3.6.9/oficonv/include/dcmtk/oficonv/iconv.h +--- dcmtk-3.6.9.orig/oficonv/include/dcmtk/oficonv/iconv.h 2025-01-21 15:53:12.637715196 +0100 ++++ dcmtk-3.6.9/oficonv/include/dcmtk/oficonv/iconv.h 2025-01-21 15:53:27.617627527 +0100 +@@ -55,7 +55,12 @@ + #endif + + struct __tag_iconv_t; ++ ++#if defined(__LSB_VERSION__) ++typedef void *iconv_t; ++#else + typedef struct __tag_iconv_t *iconv_t; ++#endif + + #ifndef OFICONV_CITRUS_WC_T_DEFINED + #define OFICONV_CITRUS_WC_T_DEFINED +diff -urEb dcmtk-3.6.9.orig/oficonv/libsrc/citrus_lock.h dcmtk-3.6.9/oficonv/libsrc/citrus_lock.h +--- dcmtk-3.6.9.orig/oficonv/libsrc/citrus_lock.h 2025-01-21 15:53:12.646715143 +0100 ++++ dcmtk-3.6.9/oficonv/libsrc/citrus_lock.h 2025-01-21 16:43:36.463693959 +0100 +@@ -31,7 +31,7 @@ + + #ifdef WITH_THREADS + +-#ifdef HAVE_WINDOWS_H ++#if defined(HAVE_WINDOWS_H) && !defined(HAVE_PTHREAD_H) /* Favor pthread if available, for MinGW */ + + #include <windows.h> + #define WLOCK(lock) AcquireSRWLockExclusive(lock); +diff -urEb dcmtk-3.6.9.orig/oflog/include/dcmtk/oflog/thread/syncpub.h dcmtk-3.6.9/oflog/include/dcmtk/oflog/thread/syncpub.h +--- dcmtk-3.6.9.orig/oflog/include/dcmtk/oflog/thread/syncpub.h 2025-01-21 15:53:12.605715381 +0100 ++++ dcmtk-3.6.9/oflog/include/dcmtk/oflog/thread/syncpub.h 2025-01-21 15:53:27.617627527 +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-3.6.9.orig/oflog/libsrc/oflog.cc dcmtk-3.6.9/oflog/libsrc/oflog.cc +--- dcmtk-3.6.9.orig/oflog/libsrc/oflog.cc 2025-01-21 15:53:12.606715376 +0100 ++++ dcmtk-3.6.9/oflog/libsrc/oflog.cc 2025-01-21 15:53:27.617627527 +0100 +@@ -19,6 +19,11 @@ + * + */ + ++ ++#if defined(_WIN32) ++# include <winsock2.h> ++#endif ++ + #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ + #include "dcmtk/oflog/oflog.h" + +diff -urEb dcmtk-3.6.9.orig/ofstd/include/dcmtk/ofstd/offile.h dcmtk-3.6.9/ofstd/include/dcmtk/ofstd/offile.h +--- dcmtk-3.6.9.orig/ofstd/include/dcmtk/ofstd/offile.h 2025-01-21 15:53:12.651715114 +0100 ++++ dcmtk-3.6.9/ofstd/include/dcmtk/ofstd/offile.h 2025-01-21 15:53:27.618627521 +0100 +@@ -569,7 +569,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 -urEb dcmtk-3.6.9.orig/ofstd/libsrc/ofstub.cc dcmtk-3.6.9/ofstd/libsrc/ofstub.cc +--- dcmtk-3.6.9.orig/ofstd/libsrc/ofstub.cc 2025-01-21 15:53:12.652715108 +0100 ++++ dcmtk-3.6.9/ofstd/libsrc/ofstub.cc 2025-01-21 15:53:27.618627521 +0100 +@@ -35,6 +35,10 @@ + #include <windows.h> + #endif /* HAVE_WINDOWS_H */ + ++#if defined(__LSB_VERSION__) ++#include <errno.h> ++#endif ++ + #define EXITCODE_CANNOT_DETERMINE_DIR 90 + #define EXITCODE_EXEC_FAILED 91 + #define EXITCODE_ILLEGAL_PARAMS 92
--- a/OrthancFramework/Resources/ProtocolBuffers/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/ProtocolBuffers/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/ProtocolBuffers/ProtobufLibrary.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/ProtocolBuffers/ProtobufLibrary.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/RetrieveCACertificates.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/RetrieveCACertificates.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Samples/MicroService/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Samples/MicroService/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Samples/MicroService/Sample.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Samples/MicroService/Sample.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/ThirdParty/icu/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/ThirdParty/icu/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/ThirdParty/icu/Version.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/ThirdParty/icu/Version.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Toolchains/CrossToolchain.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Toolchains/CrossToolchain.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Resources/WindowsResources.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Resources/WindowsResources.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/SharedLibrary/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/SharedLibrary/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/SharedLibrary/DllMain.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/SharedLibrary/DllMain.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/SharedLibrary/OrthancFramework.h.in Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/SharedLibrary/OrthancFramework.h.in Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/ICachePageProvider.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/ICachePageProvider.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/ICacheable.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/ICacheable.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/LeastRecentlyUsedIndex.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/LeastRecentlyUsedIndex.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/MemoryCache.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryCache.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/MemoryCache.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryCache.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/MemoryObjectCache.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryObjectCache.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/MemoryObjectCache.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryObjectCache.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/MemoryStringCache.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryStringCache.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/MemoryStringCache.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryStringCache.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/SharedArchive.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/SharedArchive.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Cache/SharedArchive.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Cache/SharedArchive.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/ChunkedBuffer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/ChunkedBuffer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/ChunkedBuffer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/ChunkedBuffer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compatibility.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compatibility.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/DeflateBaseCompressor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/DeflateBaseCompressor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/DeflateBaseCompressor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/DeflateBaseCompressor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/GzipCompressor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/GzipCompressor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/GzipCompressor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/GzipCompressor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/HierarchicalZipWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/HierarchicalZipWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/HierarchicalZipWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/HierarchicalZipWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/IBufferCompressor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/IBufferCompressor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/IBufferCompressor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/IBufferCompressor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/ZipReader.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/ZipReader.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/ZipReader.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/ZipReader.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/ZipWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/ZipWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/ZipWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/ZipWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/ZlibCompressor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/ZlibCompressor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Compression/ZlibCompressor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Compression/ZlibCompressor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomArray.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomArray.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomArray.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomArray.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomElement.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomElement.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomElement.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomElement.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomImageInformation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomImageInformation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomMap.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomMap.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -800,6 +800,17 @@ return false; } + bool DicomMap::HasMetaInformationTags(const std::set<DicomTag>& tags) + { + for (std::set<DicomTag>::const_iterator it = tags.begin(); it != tags.end(); ++it) + { + if (it->GetGroup() == 0x0002) + { + return true; + } + } + return false; + } void DicomMap::GetMainDicomTags(std::set<DicomTag>& target, ResourceType level) @@ -1322,7 +1333,22 @@ return value->CopyToString(result, allowBinary); } } - + + bool DicomMap::LookupStringValues(std::set<std::string>& results, + const DicomTag& tag, + bool allowBinary) const + { + std::string tmp; + if (LookupStringValue(tmp, tag, allowBinary)) + { + Toolbox::SplitString(results, tmp, '\\'); + return true; + } + + return false; + } + + bool DicomMap::ParseInteger32(int32_t& result, const DicomTag& tag) const {
--- a/OrthancFramework/Sources/DicomFormat/DicomMap.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomMap.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -146,6 +146,8 @@ static bool HasComputedTags(const std::set<DicomTag>& tags); + static bool HasMetaInformationTags(const std::set<DicomTag>& tags); + static void GetMainDicomTags(std::set<DicomTag>& target, ResourceType level); @@ -179,7 +181,11 @@ bool LookupStringValue(std::string& result, const DicomTag& tag, bool allowBinary) const; - + + bool LookupStringValues(std::set<std::string>& results, + const DicomTag& tag, + bool allowBinary) const; + bool ParseInteger32(int32_t& result, const DicomTag& tag) const;
--- a/OrthancFramework/Sources/DicomFormat/DicomPath.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomPath.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomPath.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomPath.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomStreamReader.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomStreamReader.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -247,6 +247,10 @@ pos += length + 12; } + else + { + throw OrthancException(ErrorCode_BadFileFormat, "Invalid DICOM File: Unable to parse Meta Header"); + } } if (pos != block.size())
--- a/OrthancFramework/Sources/DicomFormat/DicomStreamReader.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomStreamReader.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomTag.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomTag.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomTag.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomTag.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomValue.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomValue.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/DicomValue.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomValue.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/StreamBlockReader.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/StreamBlockReader.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomFormat/StreamBlockReader.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomFormat/StreamBlockReader.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -173,7 +173,6 @@ DicomAssociation::DicomAssociation() { - role_ = DicomAssociationRole_Default; isOpen_ = false; net_ = NULL; params_ = NULL; @@ -198,16 +197,6 @@ } - void DicomAssociation::SetRole(DicomAssociationRole role) - { - if (role_ != role) - { - Close(); - role_ = role; - } - } - - void DicomAssociation::ClearPresentationContexts() { Close(); @@ -215,7 +204,26 @@ proposed_.reserve(MAX_PROPOSED_PRESENTATIONS); } - + + static T_ASC_SC_ROLE GetDcmtkRole(DicomAssociationRole role) + { + switch (role) + { + case DicomAssociationRole_Default: + return ASC_SC_ROLE_DEFAULT; + + case DicomAssociationRole_Scu: + return ASC_SC_ROLE_SCU; + + case DicomAssociationRole_Scp: + return ASC_SC_ROLE_SCP; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + void DicomAssociation::Open(const DicomAssociationParameters& parameters) { if (isOpen_) @@ -240,24 +248,6 @@ dcmConnectionTimeout.set(acseTimeout); } - T_ASC_SC_ROLE dcmtkRole; - switch (role_) - { - case DicomAssociationRole_Default: - dcmtkRole = ASC_SC_ROLE_DEFAULT; - break; - - case DicomAssociationRole_Scu: - dcmtkRole = ASC_SC_ROLE_SCU; - break; - - case DicomAssociationRole_Scp: - dcmtkRole = ASC_SC_ROLE_SCP; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } assert(net_ == NULL && params_ == NULL && @@ -291,7 +281,12 @@ "no timeout") << ")"; CheckConnecting(parameters, ASC_initializeNetwork(NET_REQUESTOR, 0, /*opt_acse_timeout*/ acseTimeout, &net_)); +#if DCMTK_VERSION_NUMBER >= 368 + CheckConnecting(parameters, ASC_createAssociationParameters(¶ms_, parameters.GetMaximumPduLength(), acseTimeout)); +#else + // from 3.6.8, this version is obsolete CheckConnecting(parameters, ASC_createAssociationParameters(¶ms_, parameters.GetMaximumPduLength())); +#endif #if ORTHANC_ENABLE_SSL == 1 if (parameters.GetRemoteModality().IsDicomTlsEnabled()) @@ -351,12 +346,12 @@ assert(presentationContextId <= 255); const char* abstractSyntax = proposed_[i].abstractSyntax_.c_str(); - const std::set<DicomTransferSyntax>& source = proposed_[i].transferSyntaxes_; + const std::list<DicomTransferSyntax>& source = proposed_[i].transferSyntaxes_; std::vector<const char*> transferSyntaxes; transferSyntaxes.reserve(source.size()); - for (std::set<DicomTransferSyntax>::const_iterator + for (std::list<DicomTransferSyntax>::const_iterator it = source.begin(); it != source.end(); ++it) { transferSyntaxes.push_back(GetTransferSyntaxUid(*it)); @@ -365,7 +360,7 @@ assert(!transferSyntaxes.empty()); CheckConnecting(parameters, ASC_addPresentationContext( params_, presentationContextId, abstractSyntax, - &transferSyntaxes[0], transferSyntaxes.size(), dcmtkRole)); + &transferSyntaxes[0], transferSyntaxes.size(), GetDcmtkRole(proposed_[i].role_))); presentationContextId += 2; } @@ -456,36 +451,56 @@ } } + void DicomAssociation::ProposeGenericPresentationContext(const std::string& abstractSyntax, + DicomAssociationRole role) + { + std::list<DicomTransferSyntax> ts; + ts.push_back(DicomTransferSyntax_LittleEndianExplicit); // the most standard one first ! + ts.push_back(DicomTransferSyntax_LittleEndianImplicit); + ts.push_back(DicomTransferSyntax_BigEndianExplicit); // Retired but was historicaly proposed by Orthanc + ProposePresentationContext(abstractSyntax, ts, role); + } void DicomAssociation::ProposeGenericPresentationContext(const std::string& abstractSyntax) { - std::set<DicomTransferSyntax> ts; - ts.insert(DicomTransferSyntax_LittleEndianImplicit); - ts.insert(DicomTransferSyntax_LittleEndianExplicit); - ts.insert(DicomTransferSyntax_BigEndianExplicit); // Retired - ProposePresentationContext(abstractSyntax, ts); + ProposeGenericPresentationContext(abstractSyntax, DicomAssociationRole_Default); } void DicomAssociation::ProposePresentationContext(const std::string& abstractSyntax, DicomTransferSyntax transferSyntax) { - std::set<DicomTransferSyntax> ts; - ts.insert(transferSyntax); - ProposePresentationContext(abstractSyntax, ts); + ProposePresentationContext(abstractSyntax, transferSyntax, DicomAssociationRole_Default); } - + + void DicomAssociation::ProposePresentationContext(const std::string& abstractSyntax, + DicomTransferSyntax transferSyntax, + DicomAssociationRole role) + { + std::list<DicomTransferSyntax> ts; + ts.push_back(transferSyntax); + ProposePresentationContext(abstractSyntax, ts, role); + } + size_t DicomAssociation::GetRemainingPropositions() const { assert(proposed_.size() <= MAX_PROPOSED_PRESENTATIONS); return MAX_PROPOSED_PRESENTATIONS - proposed_.size(); } + void DicomAssociation::ProposePresentationContext( + const std::string& abstractSyntax, + const std::list<DicomTransferSyntax>& transferSyntaxes) + { + ProposePresentationContext(abstractSyntax, transferSyntaxes, DicomAssociationRole_Default); + } + void DicomAssociation::ProposePresentationContext( const std::string& abstractSyntax, - const std::set<DicomTransferSyntax>& transferSyntaxes) + const std::list<DicomTransferSyntax>& transferSyntaxes, + DicomAssociationRole role) { if (transferSyntaxes.empty()) { @@ -507,6 +522,7 @@ ProposedPresentationContext context; context.abstractSyntax_ = abstractSyntax; context.transferSyntaxes_ = transferSyntaxes; + context.role_ = role; proposed_.push_back(context); } @@ -526,6 +542,35 @@ } } + bool DicomAssociation::GetAssociationParameters(std::string& remoteAet, + std::string& remoteIp, + std::string& calledAet) const + { + T_ASC_Association& dcmtkAssoc = GetDcmtkAssociation(); + + DIC_AE remoteAet_C; + DIC_AE calledAet_C; + DIC_AE remoteIp_C; + DIC_AE calledIP_C; + + if ( +#if DCMTK_VERSION_NUMBER >= 364 + ASC_getAPTitles(dcmtkAssoc.params, remoteAet_C, sizeof(remoteAet_C), calledAet_C, sizeof(calledAet_C), NULL, 0).good() && + ASC_getPresentationAddresses(dcmtkAssoc.params, remoteIp_C, sizeof(remoteIp_C), calledIP_C, sizeof(calledIP_C)).good() +#else + ASC_getAPTitles(dcmtkAssoc.params, remoteAet_C, calledAet_C, NULL).good() && + ASC_getPresentationAddresses(dcmtkAssoc.params, remoteIp_C, calledIP_C).good() +#endif + ) + { + remoteIp = std::string(/*OFSTRING_GUARD*/(remoteIp_C)); + remoteAet = std::string(/*OFSTRING_GUARD*/(remoteAet_C)); + calledAet = (/*OFSTRING_GUARD*/(calledAet_C)); + return true; + } + + return false; + } T_ASC_Network& DicomAssociation::GetDcmtkNetwork() const { @@ -649,13 +694,12 @@ DicomAssociation association; { - std::set<DicomTransferSyntax> transferSyntaxes; - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); + std::list<DicomTransferSyntax> transferSyntaxes; + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianExplicit); + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianImplicit); - association.SetRole(DicomAssociationRole_Scp); association.ProposePresentationContext(UID_StorageCommitmentPushModelSOPClass, - transferSyntaxes); + transferSyntaxes, DicomAssociationRole_Scp); } association.Open(parameters); @@ -828,13 +872,13 @@ DicomAssociation association; { - std::set<DicomTransferSyntax> transferSyntaxes; - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); + std::list<DicomTransferSyntax> transferSyntaxes; + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianExplicit); + transferSyntaxes.push_back(DicomTransferSyntax_LittleEndianImplicit); - association.SetRole(DicomAssociationRole_Default); + // association.SetRole(DicomAssociationRole_Default); association.ProposePresentationContext(UID_StorageCommitmentPushModelSOPClass, - transferSyntaxes); + transferSyntaxes, DicomAssociationRole_Default); } association.Open(parameters);
--- a/OrthancFramework/Sources/DicomNetworking/DicomAssociation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,6 +44,7 @@ #include <stdint.h> // For uint8_t #include <boost/noncopyable.hpp> #include <set> +#include <list> namespace Orthanc { @@ -58,13 +59,13 @@ struct ProposedPresentationContext { std::string abstractSyntax_; - std::set<DicomTransferSyntax> transferSyntaxes_; + std::list<DicomTransferSyntax> transferSyntaxes_; + DicomAssociationRole role_; }; typedef std::map<std::string, std::map<DicomTransferSyntax, uint8_t> > AcceptedPresentationContexts; - DicomAssociationRole role_; bool isOpen_; std::vector<ProposedPresentationContext> proposed_; AcceptedPresentationContexts accepted_; @@ -95,8 +96,6 @@ return isOpen_; } - void SetRole(DicomAssociationRole role); - void ClearPresentationContexts(); void Open(const DicomAssociationParameters& parameters); @@ -109,6 +108,13 @@ void ProposeGenericPresentationContext(const std::string& abstractSyntax); + void ProposeGenericPresentationContext(const std::string& abstractSyntax, + DicomAssociationRole role); + + void ProposePresentationContext(const std::string& abstractSyntax, + DicomTransferSyntax transferSyntax, + DicomAssociationRole role); + void ProposePresentationContext(const std::string& abstractSyntax, DicomTransferSyntax transferSyntax); @@ -116,12 +122,21 @@ void ProposePresentationContext( const std::string& abstractSyntax, - const std::set<DicomTransferSyntax>& transferSyntaxes); - + const std::list<DicomTransferSyntax>& transferSyntaxes); + + void ProposePresentationContext( + const std::string& abstractSyntax, + const std::list<DicomTransferSyntax>& transferSyntaxes, + DicomAssociationRole role); + T_ASC_Association& GetDcmtkAssociation() const; T_ASC_Network& GetDcmtkNetwork() const; + bool GetAssociationParameters(std::string& remoteAet, + std::string& remoteIp, + std::string& calledAet) const; + static void CheckCondition(const OFCondition& cond, const DicomAssociationParameters& parameters, const std::string& command);
--- a/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -234,15 +234,58 @@ - void DicomControlUserConnection::SetupPresentationContexts() + void DicomControlUserConnection::SetupPresentationContexts( + ScuOperationFlags scuOperation, + const std::set<std::string>& acceptedStorageSopClasses, + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes) { assert(association_.get() != NULL); - association_->ProposeGenericPresentationContext(UID_VerificationSOPClass); - association_->ProposeGenericPresentationContext(UID_FINDPatientRootQueryRetrieveInformationModel); - association_->ProposeGenericPresentationContext(UID_MOVEPatientRootQueryRetrieveInformationModel); - association_->ProposeGenericPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel); - association_->ProposeGenericPresentationContext(UID_MOVEStudyRootQueryRetrieveInformationModel); - association_->ProposeGenericPresentationContext(UID_FINDModalityWorklistInformationModel); + + if ((scuOperation & ScuOperationFlags_Echo) != 0) + { + association_->ProposeGenericPresentationContext(UID_VerificationSOPClass); + } + + if ((scuOperation & ScuOperationFlags_FindPatient) != 0) + { + association_->ProposeGenericPresentationContext(UID_FINDPatientRootQueryRetrieveInformationModel); + } + + if ((scuOperation & ScuOperationFlags_FindStudy) != 0) + { + association_->ProposeGenericPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel); + } + + if ((scuOperation & ScuOperationFlags_FindWorklist) != 0) + { + association_->ProposeGenericPresentationContext(UID_FINDModalityWorklistInformationModel); + } + + if ((scuOperation & ScuOperationFlags_MovePatient) != 0) + { + association_->ProposeGenericPresentationContext(UID_MOVEPatientRootQueryRetrieveInformationModel); + } + + if ((scuOperation & ScuOperationFlags_MoveStudy) != 0) + { + association_->ProposeGenericPresentationContext(UID_MOVEStudyRootQueryRetrieveInformationModel); + } + + if ((scuOperation & ScuOperationFlags_Get) != 0) + { + association_->ProposeGenericPresentationContext(UID_GETStudyRootQueryRetrieveInformationModel); + association_->ProposeGenericPresentationContext(UID_GETPatientRootQueryRetrieveInformationModel); + + if (acceptedStorageSopClasses.size() == 0) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); // the acceptedStorageSopClassUids should always be defined for a C-Get + } + + for (std::set<std::string>::const_iterator it = acceptedStorageSopClasses.begin(); it != acceptedStorageSopClasses.end(); ++it) + { + association_->ProposePresentationContext(*it, proposedStorageTransferSyntaxes, DicomAssociationRole_Scp); + } + } } @@ -350,6 +393,21 @@ } } + void MoveProgressCallback(void *callbackData, + T_DIMSE_C_MoveRQ *request, + int responseCount, + T_DIMSE_C_MoveRSP *response) + { + DicomControlUserConnection::IProgressListener* listener = reinterpret_cast<DicomControlUserConnection::IProgressListener*>(callbackData); + if (listener) + { + listener->OnProgressUpdated(response->NumberOfRemainingSubOperations, + response->NumberOfCompletedSubOperations, + response->NumberOfFailedSubOperations, + response->NumberOfWarningSubOperations); + } + } + void DicomControlUserConnection::MoveInternal(const std::string& targetAet, ResourceType level, @@ -391,7 +449,8 @@ DcmDataset* statusDetail = NULL; DcmDataset* responseIdentifiers = NULL; OFCondition cond = DIMSE_moveUser( - &association_->GetDcmtkAssociation(), presID, &request, dataset, /*moveCallback*/ NULL, NULL, + &association_->GetDcmtkAssociation(), presID, &request, dataset, + (progressListener_ != NULL ? MoveProgressCallback : NULL), progressListener_, /*opt_blockMode*/ (parameters_.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), /*opt_dimse_timeout*/ parameters_.GetTimeout(), &association_->GetDcmtkNetwork(), /*subOpCallback*/ NULL, NULL, @@ -413,6 +472,14 @@ OFString str; CLOG(TRACE, DICOM) << "Received Final Move Response:" << std::endl << DIMSE_dumpMessage(str, response, DIMSE_INCOMING); + + if (progressListener_ != NULL) + { + progressListener_->OnProgressUpdated(response.NumberOfRemainingSubOperations, + response.NumberOfCompletedSubOperations, + response.NumberOfFailedSubOperations, + response.NumberOfWarningSubOperations); + } } /** @@ -445,11 +512,240 @@ } - DicomControlUserConnection::DicomControlUserConnection(const DicomAssociationParameters& params) : + void DicomControlUserConnection::Get(const DicomMap& findResult, + CGetInstanceReceivedCallback instanceReceivedCallback, + void* callbackContext) + { + assert(association_.get() != NULL); + association_->Open(parameters_); + + std::unique_ptr<ParsedDicomFile> query( + ConvertQueryFields(findResult, parameters_.GetRemoteModality().GetManufacturer())); + DcmDataset* queryDataset = query->GetDcmtkObject().getDataset(); + + std::string remoteAet; + std::string remoteIp; + std::string calledAet; + + association_->GetAssociationParameters(remoteAet, remoteIp, calledAet); + + const char* sopClass = NULL; + const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).GetContent(); + ResourceType level = StringToResourceType(tmp.c_str()); + switch (level) + { + case ResourceType_Patient: + sopClass = UID_GETPatientRootQueryRetrieveInformationModel; + break; + case ResourceType_Study: + case ResourceType_Series: + case ResourceType_Instance: + sopClass = UID_GETStudyRootQueryRetrieveInformationModel; + break; + default: + throw OrthancException(ErrorCode_InternalError); + } + + // Figure out which of the accepted presentation contexts should be used + int cgetPresID = ASC_findAcceptedPresentationContextID(&association_->GetDcmtkAssociation(), sopClass); + if (cgetPresID == 0) + { + throw OrthancException(ErrorCode_DicomGetUnavailable, + "Remote AET is " + parameters_.GetRemoteModality().GetApplicationEntityTitle()); + } + + T_DIMSE_Message msgGetRequest; + memset((char*)&msgGetRequest, 0, sizeof(msgGetRequest)); + msgGetRequest.CommandField = DIMSE_C_GET_RQ; + + T_DIMSE_C_GetRQ* request = &(msgGetRequest.msg.CGetRQ); + request->MessageID = association_->GetDcmtkAssociation().nextMsgID++; + strncpy(request->AffectedSOPClassUID, sopClass, DIC_UI_LEN); + request->Priority = DIMSE_PRIORITY_MEDIUM; + request->DataSetType = DIMSE_DATASET_PRESENT; + + { + OFString str; + CLOG(TRACE, DICOM) << "Sending Get Request:" << std::endl + << DIMSE_dumpMessage(str, *request, DIMSE_OUTGOING, NULL, cgetPresID); + } + + OFCondition cond = DIMSE_sendMessageUsingMemoryData( + &(association_->GetDcmtkAssociation()), cgetPresID, &msgGetRequest, NULL /* statusDetail */, queryDataset, + NULL, NULL, NULL /* commandSet */); + + if (cond.bad()) + { + OFString tempStr; + CLOG(TRACE, DICOM) << "Failed sending C-GET request: " << DimseCondition::dump(tempStr, cond); + // return cond; + } + + // equivalent to handleCGETSession in DCMTK + bool continueSession = true; + + // As long we want to continue (usually, as long as we receive more objects, + // i.e. the final C-GET response has not arrived yet) + while (continueSession) + { + T_DIMSE_Message rsp; + // Make sure everything is zeroed (especially options) + memset((char*)&rsp, 0, sizeof(rsp)); + + // DcmDataset* statusDetail = NULL; + T_ASC_PresentationContextID cmdPresId = 0; + + OFCondition result = DIMSE_receiveCommand(&(association_->GetDcmtkAssociation()), + (parameters_.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), + parameters_.GetTimeout(), + &cmdPresId, + &rsp, + NULL /* statusDetail */, + NULL /* not interested in the command set */); + + if (result.bad()) + { + OFString tempStr; + CLOG(TRACE, DICOM) << "Failed receiving DIMSE command: " << DimseCondition::dump(tempStr, result); + // delete statusDetail; + break; // TODO: return value + } + // Handle C-GET Response + if (rsp.CommandField == DIMSE_C_GET_RSP) + { + { + OFString tempStr; + CLOG(TRACE, DICOM) << "Received C-GET Response: " << std::endl + << DIMSE_dumpMessage(tempStr, rsp, DIMSE_INCOMING, NULL, cmdPresId); + } + + if (progressListener_ != NULL) + { + progressListener_->OnProgressUpdated(rsp.msg.CGetRSP.NumberOfRemainingSubOperations, + rsp.msg.CGetRSP.NumberOfCompletedSubOperations, + rsp.msg.CGetRSP.NumberOfFailedSubOperations, + rsp.msg.CGetRSP.NumberOfWarningSubOperations); + } + + if (rsp.msg.CGetRSP.DimseStatus == 0x0000) // final success message + { + continueSession = false; + } + } + // Handle C-STORE Request + else if (rsp.CommandField == DIMSE_C_STORE_RQ) + { + { + OFString tempStr; + CLOG(TRACE, DICOM) << "Received C-STORE Request: " << std::endl + << DIMSE_dumpMessage(tempStr, rsp, DIMSE_INCOMING, NULL, cmdPresId); + } + + T_DIMSE_C_StoreRQ* storeRequest = &(rsp.msg.CStoreRQ); + + // Check if dataset is announced correctly + if (rsp.msg.CStoreRQ.DataSetType == DIMSE_DATASET_NULL) + { + CLOG(WARNING, DICOM) << "C-GET SCU handler: Incoming C-STORE with no dataset"; + } + + Uint16 desiredCStoreReturnStatus = 0; + DcmDataset* dataObject = NULL; + + // Receive dataset + result = DIMSE_receiveDataSetInMemory(&(association_->GetDcmtkAssociation()), + (parameters_.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), + parameters_.GetTimeout(), + &cmdPresId, + &dataObject, + NULL, NULL); + + if (result.bad()) + { + LOG(WARNING) << "C-GET SCU handler: Failed to receive dataset: " << result.text(); + desiredCStoreReturnStatus = STATUS_STORE_Error_CannotUnderstand; + } + else + { + // callback the OrthancServer with the received data + if (instanceReceivedCallback != NULL) + { + desiredCStoreReturnStatus = instanceReceivedCallback(callbackContext, *dataObject, remoteAet, remoteIp, calledAet); + } + + // send the Store response + T_DIMSE_Message storeResponse; + memset((char*)&storeResponse, 0, sizeof(storeResponse)); + storeResponse.CommandField = DIMSE_C_STORE_RSP; + + T_DIMSE_C_StoreRSP& storeRsp = storeResponse.msg.CStoreRSP; + storeRsp.MessageIDBeingRespondedTo = storeRequest->MessageID; + storeRsp.DimseStatus = desiredCStoreReturnStatus; + storeRsp.DataSetType = DIMSE_DATASET_NULL; + + OFStandard::strlcpy( + storeRsp.AffectedSOPClassUID, storeRequest->AffectedSOPClassUID, sizeof(storeRsp.AffectedSOPClassUID)); + OFStandard::strlcpy( + storeRsp.AffectedSOPInstanceUID, storeRequest->AffectedSOPInstanceUID, sizeof(storeRsp.AffectedSOPInstanceUID)); + storeRsp.opts = O_STORE_AFFECTEDSOPCLASSUID | O_STORE_AFFECTEDSOPINSTANCEUID; + + result = DIMSE_sendMessageUsingMemoryData(&(association_->GetDcmtkAssociation()), + cmdPresId, + &storeResponse, NULL /* statusDetail */, NULL /* dataObject */, + NULL, NULL, NULL /* commandSet */); + if (result.bad()) + { + continueSession = false; + } + else + { + OFString tempStr; + CLOG(TRACE, DICOM) << "Sent C-STORE Response: " << std::endl + << DIMSE_dumpMessage(tempStr, storeResponse, DIMSE_OUTGOING, NULL, cmdPresId); + } + } + } + // Handle other DIMSE command (error since other command than GET/STORE not expected) + else + { + CLOG(WARNING, DICOM) << "Expected C-GET response or C-STORE request but received DIMSE command 0x" + << std::hex << std::setfill('0') << std::setw(4) + << static_cast<unsigned int>(rsp.CommandField); + + result = DIMSE_BADCOMMANDTYPE; + continueSession = false; + } + + // delete statusDetail; // should be NULL if not existing or added to response list + // statusDetail = NULL; + } + /* All responses received or break signal occurred */ + + // return result; +} + + + DicomControlUserConnection::DicomControlUserConnection(const DicomAssociationParameters& params, ScuOperationFlags scuOperation) : parameters_(params), - association_(new DicomAssociation) + association_(new DicomAssociation), + progressListener_(NULL) { - SetupPresentationContexts(); + assert((scuOperation & ScuOperationFlags_Get) == 0); // you must provide acceptedStorageSopClassUids for Get SCU + std::set<std::string> emptyStorageSopClasses; + std::list<DicomTransferSyntax> emptyStorageTransferSyntaxes; + + SetupPresentationContexts(scuOperation, emptyStorageSopClasses, emptyStorageTransferSyntaxes); + } + + DicomControlUserConnection::DicomControlUserConnection(const DicomAssociationParameters& params, + ScuOperationFlags scuOperation, + const std::set<std::string>& acceptedStorageSopClasses, + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes) : + parameters_(params), + association_(new DicomAssociation), + progressListener_(NULL) + { + SetupPresentationContexts(scuOperation, acceptedStorageSopClasses, proposedStorageTransferSyntaxes); }
--- a/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,18 +32,55 @@ #include "DicomFindAnswers.h" #include <boost/noncopyable.hpp> +#include <list> namespace Orthanc { class DicomAssociation; // Forward declaration for PImpl design pattern + typedef uint16_t (*CGetInstanceReceivedCallback) (void *callbackContext, + DcmDataset& dataset, + const std::string& remoteAet, + const std::string& remoteIp, + const std::string& calledAet); + + + enum ScuOperationFlags + { + ScuOperationFlags_Echo = 1 << 0, + ScuOperationFlags_FindPatient = 1 << 1, + ScuOperationFlags_FindStudy = 1 << 2, + ScuOperationFlags_FindWorklist = 1 << 3, + ScuOperationFlags_MoveStudy = 1 << 4, + ScuOperationFlags_MovePatient = 1 << 5, + // C-Store is not using DicomControlUserConnection but DicomStoreUserConnection + ScuOperationFlags_Get = 1 << 6, + + ScuOperationFlags_Find = ScuOperationFlags_FindPatient | ScuOperationFlags_FindStudy | ScuOperationFlags_FindWorklist, + ScuOperationFlags_Move = ScuOperationFlags_MoveStudy | ScuOperationFlags_MovePatient, + ScuOperationFlags_All = ScuOperationFlags_Echo | ScuOperationFlags_Find | ScuOperationFlags_Move | ScuOperationFlags_Get + }; + class DicomControlUserConnection : public boost::noncopyable { + public: + class IProgressListener + { + public: + virtual void OnProgressUpdated(uint16_t nbRemainingSubOperations, + uint16_t nbCompletedSubOperations, + uint16_t nbFailedSubOperations, + uint16_t nbWarningSubOperations) = 0; + }; + private: DicomAssociationParameters parameters_; boost::shared_ptr<DicomAssociation> association_; + IProgressListener* progressListener_; - void SetupPresentationContexts(); + void SetupPresentationContexts(ScuOperationFlags scuOperation, + const std::set<std::string>& acceptedStorageSopClasses, + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes); void FindInternal(DicomFindAnswers& answers, DcmDataset* dataset, @@ -56,8 +93,14 @@ const DicomMap& fields); public: - explicit DicomControlUserConnection(const DicomAssociationParameters& params); - + explicit DicomControlUserConnection(const DicomAssociationParameters& params, ScuOperationFlags scuOperation); + + // specific constructor for CGet SCU + explicit DicomControlUserConnection(const DicomAssociationParameters& params, + ScuOperationFlags scuOperation, + const std::set<std::string>& acceptedStorageSopClasses, + const std::list<DicomTransferSyntax>& proposedStorageTransferSyntaxes); + const DicomAssociationParameters& GetParameters() const { return parameters_; @@ -67,11 +110,20 @@ bool Echo(); + void SetProgressListener(IProgressListener* progressListener) + { + progressListener_ = progressListener; + } + void Find(DicomFindAnswers& result, ResourceType level, const DicomMap& originalFields, bool normalize); + void Get(const DicomMap& getQuery, + CGetInstanceReceivedCallback instanceReceivedCallback, + void* callbackContext); + void Move(const std::string& targetAet, ResourceType level, const DicomMap& findResult);
--- a/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -202,7 +202,7 @@ DicomToJsonFormat format) const { const ParsedDicomFile& answer = GetAnswer(index); - answer.DatasetToJson(target, format, DicomToJsonFlags_None, 0); + answer.DatasetToJson(target, format, DicomToJsonFlags_IncludePrivateTags, 0); }
--- a/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/DicomServer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomServer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/DicomServer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomServer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -57,7 +57,7 @@ bool hasPreferred, DicomTransferSyntax preferred) { - typedef std::list< std::set<DicomTransferSyntax> > GroupsOfSyntaxes; + typedef std::list< std::list<DicomTransferSyntax> > GroupsOfSyntaxes; GroupsOfSyntaxes groups; @@ -65,8 +65,8 @@ for (std::set<DicomTransferSyntax>::const_iterator it = sourceSyntaxes.begin(); it != sourceSyntaxes.end(); ++it) { - std::set<DicomTransferSyntax> group; - group.insert(*it); + std::list<DicomTransferSyntax> group; + group.push_back(*it); groups.push_back(group); } @@ -74,8 +74,8 @@ if (hasPreferred && sourceSyntaxes.find(preferred) == sourceSyntaxes.end()) { - std::set<DicomTransferSyntax> group; - group.insert(preferred); + std::list<DicomTransferSyntax> group; + group.push_back(preferred); groups.push_back(group); } @@ -89,7 +89,7 @@ DicomTransferSyntax_BigEndianExplicit }; - std::set<DicomTransferSyntax> group; + std::list<DicomTransferSyntax> group; for (size_t i = 0; i < N; i++) { @@ -97,7 +97,7 @@ if (sourceSyntaxes.find(syntax) == sourceSyntaxes.end() && (!hasPreferred || preferred != syntax)) { - group.insert(syntax); + group.push_back(syntax); } } @@ -651,7 +651,7 @@ s += " " + std::string(GetTransferSyntaxUid(*it)); } - throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode instance of SOPClassUID " + + throw OrthancException(ErrorCode_InternalError, "Cannot transcode instance of SOPClassUID " + sopClassUid + " from " + std::string(GetTransferSyntaxUid(sourceSyntax)) + " to one of [" + s + " ]");
--- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IApplicationEntityFilter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IApplicationEntityFilter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +28,7 @@ #include <boost/noncopyable.hpp> #include <string> +#include <list> namespace Orthanc { @@ -47,13 +48,23 @@ const std::string& calledAet, DicomRequestType type) = 0; + // Get the set of TransferSyntaxes that are accepted when negotiation a C-Store association, acting as SCP when it has been initiated by the C-Store SCU. virtual void GetAcceptedTransferSyntaxes(std::set<DicomTransferSyntax>& target, const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) = 0; - + + // Get the list of TransferSyntaxes that are proposed when initiating a C-Store SCP which actually only happens in a C-Get SCU + virtual void GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) = 0; + virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) = 0; + + virtual void GetAcceptedSopClasses(std::set<std::string>& sopClasses, + size_t maxCount) = 0; }; }
--- a/OrthancFramework/Sources/DicomNetworking/IFindRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IFindRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IFindRequestHandlerFactory.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IFindRequestHandlerFactory.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IGetRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IGetRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IGetRequestHandlerFactory.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IGetRequestHandlerFactory.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandlerFactory.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandlerFactory.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandlerFactory.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandlerFactory.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandlerFactory.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandlerFactory.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -502,13 +502,21 @@ } else // see dcmqrsrv.cc lines 839 - 876 { + std::set<std::string> acceptedStorageClasses; + + if (server.HasApplicationEntityFilter()) + { + server.GetApplicationEntityFilter().GetAcceptedSopClasses(acceptedStorageClasses, 0); + } + /* accept storage syntaxes with proposed role */ int npc = ASC_countPresentationContexts(assoc->params); for (int i = 0; i < npc; i++) { T_ASC_PresentationContext pc; ASC_getPresentationContext(assoc->params, i, &pc); - if (dcmIsaStorageSOPClassUID(pc.abstractSyntax)) + if (acceptedStorageClasses.find(pc.abstractSyntax) != acceptedStorageClasses.end() + || (!server.HasApplicationEntityFilter() && dcmIsaStorageSOPClassUID(pc.abstractSyntax))) // previous behavior kept for compatibility in case the server does not have an ApplicationEntityFilter { /** * We are prepared to accept whatever role the caller
--- a/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,6 +44,16 @@ #endif +#if ORTHANC_ENABLE_PLUGINS == 1 +# if defined(__ORTHANC_FILE__) +// Prevents the system-wide DCMTK library from leaking the +// full path of this source file in "DCMTLS_ERROR()" +# undef __FILE__ +# define __FILE__ __ORTHANC_FILE__ +# endif +#endif + + namespace Orthanc { namespace Internals
--- a/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/NetworkingCompatibility.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/NetworkingCompatibility.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,6 +50,7 @@ static const char* KEY_USE_DICOM_TLS = "UseDicomTls"; static const char* KEY_LOCAL_AET = "LocalAet"; static const char* KEY_TIMEOUT = "Timeout"; +static const char* KEY_RETRIEVE_METHOD = "RetrieveMethod"; namespace Orthanc @@ -72,6 +73,7 @@ useDicomTls_ = false; localAet_.clear(); timeout_ = 0; + retrieveMethod_ = RetrieveMethod_SystemDefault; } @@ -308,6 +310,17 @@ { timeout_ = SerializationToolbox::ReadUnsignedInteger(serialized, KEY_TIMEOUT); } + + if (serialized.isMember(KEY_RETRIEVE_METHOD)) + { + retrieveMethod_ = StringToRetrieveMethod + (SerializationToolbox::ReadString(serialized, KEY_RETRIEVE_METHOD)); + } + else + { + retrieveMethod_ = RetrieveMethod_SystemDefault; + } + } @@ -427,6 +440,7 @@ target[KEY_USE_DICOM_TLS] = useDicomTls_; target[KEY_LOCAL_AET] = localAet_; target[KEY_TIMEOUT] = timeout_; + target[KEY_RETRIEVE_METHOD] = EnumerationToString(retrieveMethod_); } else { @@ -521,4 +535,14 @@ { return timeout_ != 0; } + + RetrieveMethod RemoteModalityParameters::GetRetrieveMethod() const + { + return retrieveMethod_; + } + + void RemoteModalityParameters::SetRetrieveMethod(RetrieveMethod retrieveMethod) + { + retrieveMethod_ = retrieveMethod; + } }
--- a/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,6 +51,7 @@ bool useDicomTls_; std::string localAet_; uint32_t timeout_; + RetrieveMethod retrieveMethod_; // New in Orthanc 1.12.6 void Clear(); @@ -118,5 +119,10 @@ uint32_t GetTimeout() const; bool HasTimeout() const; + + RetrieveMethod GetRetrieveMethod() const; + + void SetRetrieveMethod(RetrieveMethod retrieveMethod); + }; }
--- a/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,8 +50,9 @@ namespace Orthanc { - DcmtkTranscoder::DcmtkTranscoder() : - lossyQuality_(90) + DcmtkTranscoder::DcmtkTranscoder(unsigned int maxConcurrentExecutions) : + lossyQuality_(90), + maxConcurrentExecutionsSemaphore_(maxConcurrentExecutions) { } @@ -317,6 +318,8 @@ const std::set<DicomTransferSyntax>& allowedSyntaxes, bool allowNewSopInstanceUid) { + Semaphore::Locker lock(maxConcurrentExecutionsSemaphore_); // limit the number of concurrent executions + target.Clear(); DicomTransferSyntax sourceSyntax;
--- a/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +33,8 @@ #endif #include "IDicomTranscoder.h" +#include "../MultiThreading/Semaphore.h" + namespace Orthanc { @@ -40,7 +42,8 @@ { private: unsigned int lossyQuality_; - + Semaphore maxConcurrentExecutionsSemaphore_; + bool InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */, std::string& failureReason /* out */, DcmFileFormat& dicom, @@ -48,7 +51,7 @@ bool allowNewSopInstanceUid); public: - DcmtkTranscoder(); + explicit DcmtkTranscoder(unsigned int maxConcurrentExecutions); void SetLossyQuality(unsigned int quality);
--- a/OrthancFramework/Sources/DicomParsing/DicomDirWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomDirWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/DicomDirWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomDirWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +28,7 @@ #include "../Logging.h" #include "../OrthancException.h" #include "../Toolbox.h" +#include "../SerializationToolbox.h" #include "FromDcmtkBridge.h" #include <boost/math/special_functions/round.hpp> @@ -341,6 +342,31 @@ } } + Json::Value DicomWebJsonVisitor::FormatDecimalString(double value, const std::string& originalString) + { + try + { + long long a = boost::math::llround<double>(value); + + double d = fabs(value - static_cast<double>(a)); + + if (d <= std::numeric_limits<double>::epsilon() * 100.0) + { + return FormatInteger(a); // if the decimal number is an integer, you can represent it as an integer + } + else + { + return Json::Value(originalString); // keep the original string to avoid rounding errors e.g, transforming "0.143" into 0.14299999999999 + } + } + catch (boost::math::rounding_error&) + { + // Can occur if "long long" is too small to receive this value + // (e.g. infinity) + return Json::Value(originalString); + } + } + DicomWebJsonVisitor::DicomWebJsonVisitor() : formatter_(NULL) { @@ -677,14 +703,33 @@ case ValueRepresentation_DecimalString: { std::string t = Toolbox::StripSpaces(tokens[i]); + boost::replace_all(t, ",", "."); // some invalid files uses "," instead of "." + + // remove invalid/useless trailing decimal separator + if (t.size() > 0 && t[t.size()-1] == '.') + { + t.resize(t.size() -1); + } + if (t.empty()) { node[KEY_VALUE].append(Json::nullValue); } else { - double tmp = boost::lexical_cast<double>(t); - node[KEY_VALUE].append(FormatDouble(tmp)); + // https://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.3.html + // DS values can be represented as String or Number in Json. + // For IS, DS, SV and UV, a JSON String representation can be used to preserve the original format during transformation of the representation, or if needed to avoid losing precision of a decimal string. + // Since 1.12.5, always use the string repesentation. Before, decimal numbers were represented as double which led to loss of precision (e.g: 0.143 represented as 0.1429999999) + double tmp; + if (SerializationToolbox::ParseDouble(tmp, t)) // make sure that the string contains a valid decimal number + { + node[KEY_VALUE].append(t); + } + else + { + throw boost::bad_lexical_cast(); + } } break;
--- a/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -74,6 +74,8 @@ static Json::Value FormatDouble(double value); + static Json::Value FormatDecimalString(double value, const std::string& originalString); + public: DicomWebJsonVisitor();
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ITagVisitor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ITagVisitor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Endianness.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Endianness.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/EnumerationDictionary.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/EnumerationDictionary.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Enumerations.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Enumerations.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -372,6 +372,9 @@ case ErrorCode_NoCGetHandler: return "No request handler factory for DICOM C-GET SCP"; + case ErrorCode_DicomGetUnavailable: + return "DicomUserConnection: The C-GET command is not supported by the remote SCP"; + case ErrorCode_UnsupportedMediaType: return "Unsupported media type"; @@ -2493,6 +2496,44 @@ } } + RetrieveMethod StringToRetrieveMethod(const std::string& str) + { + if (str == "C-MOVE") + { + return RetrieveMethod_Move; + } + else if (str == "C-GET") + { + return RetrieveMethod_Get; + } + else if (str == "SystemDefault") + { + return RetrieveMethod_SystemDefault; + } + else + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "RetrieveMethod can be \"C-MOVE\", \"C-GET\" or \"SystemDefault\": " + str); + } + } + + const char* EnumerationToString(RetrieveMethod method) + { + switch (method) + { + case RetrieveMethod_Get: + return "C-GET"; + + case RetrieveMethod_Move: + return "C-MOVE"; + + case RetrieveMethod_SystemDefault: + return "SystemDefault"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } }
--- a/OrthancFramework/Sources/Enumerations.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Enumerations.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -234,6 +234,7 @@ ErrorCode_AlreadyExistingTag = 2042 /*!< Cannot override the value of a tag that already exists */, ErrorCode_NoStorageCommitmentHandler = 2043 /*!< No request handler factory for DICOM N-ACTION SCP (storage commitment) */, ErrorCode_NoCGetHandler = 2044 /*!< No request handler factory for DICOM C-GET SCP */, + ErrorCode_DicomGetUnavailable = 2045 /*!< DicomUserConnection: The C-GET command is not supported by the remote SCP */, ErrorCode_UnsupportedMediaType = 3000 /*!< Unsupported media type */, ErrorCode_START_PLUGINS = 1000000 }; @@ -793,6 +794,14 @@ ResourceType_Instance = 4 }; + enum RetrieveMethod // new in Orthanc 1.12.6 + { + RetrieveMethod_Move = 1, + RetrieveMethod_Get = 2, + + RetrieveMethod_SystemDefault = 65535 + }; + ORTHANC_PUBLIC const char* EnumerationToString(ErrorCode code); @@ -849,6 +858,9 @@ const char* EnumerationToString(DicomToJsonFormat format); ORTHANC_PUBLIC + const char* EnumerationToString(RetrieveMethod method); + + ORTHANC_PUBLIC Encoding StringToEncoding(const char* encoding); ORTHANC_PUBLIC @@ -947,4 +959,7 @@ ORTHANC_PUBLIC void GetAllDicomTransferSyntaxes(std::set<DicomTransferSyntax>& target); + + ORTHANC_PUBLIC + RetrieveMethod StringToRetrieveMethod(const std::string& str); }
--- a/OrthancFramework/Sources/Enumerations_TransferSyntaxes.impl.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Enumerations_TransferSyntaxes.impl.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileBuffer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileBuffer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileBuffer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileBuffer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/FileInfo.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/FileInfo.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/FileInfo.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/FileInfo.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -176,11 +176,11 @@ LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; return; } - catch (OrthancException& ex) + catch (OrthancException& e) { if (retryCount >= maxRetryCount) { - throw ex; + throw; } } }
--- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/IStorageArea.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/IStorageArea.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,16 +28,18 @@ #include "../Logging.h" #include "../StringMemoryBuffer.h" -#include "../Compatibility.h" #include "../Compression/ZlibCompressor.h" #include "../MetricsRegistry.h" #include "../OrthancException.h" +#include "../SerializationToolbox.h" #include "../Toolbox.h" #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 # include "../HttpServer/HttpStreamTranscoder.h" #endif +#include <boost/algorithm/string.hpp> + static const std::string METRICS_CREATE_DURATION = "orthanc_storage_create_duration_ms"; static const std::string METRICS_READ_DURATION = "orthanc_storage_read_duration_ms"; @@ -50,6 +52,212 @@ namespace Orthanc { + void StorageAccessor::Range::SanityCheck() const + { + if (hasStart_ && hasEnd_ && start_ > end_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + } + + StorageAccessor::Range::Range(): + hasStart_(false), + start_(0), + hasEnd_(false), + end_(0) + { + } + + void StorageAccessor::Range::SetStartInclusive(uint64_t start) + { + hasStart_ = true; + start_ = start; + } + + void StorageAccessor::Range::SetEndInclusive(uint64_t end) + { + hasEnd_ = true; + end_ = end; + } + + uint64_t StorageAccessor::Range::GetStartInclusive() const + { + if (!hasStart_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else if (hasEnd_ && start_ > end_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + return start_; + } + } + + uint64_t StorageAccessor::Range::GetEndInclusive() const + { + if (!hasEnd_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else if (hasStart_ && start_ > end_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + return end_; + } + } + + std::string StorageAccessor::Range::FormatHttpContentRange(uint64_t fullSize) const + { + SanityCheck(); + + if (fullSize == 0 || + (hasStart_ && start_ >= fullSize) || + (hasEnd_ && end_ >= fullSize)) + { + throw OrthancException(ErrorCode_BadRange); + } + + std::string s = "bytes "; + + if (hasStart_) + { + s += boost::lexical_cast<std::string>(start_); + } + else + { + s += "0"; + } + + s += "-"; + + if (hasEnd_) + { + s += boost::lexical_cast<std::string>(end_); + } + else + { + s += boost::lexical_cast<std::string>(fullSize - 1); + } + + return s + "/" + boost::lexical_cast<std::string>(fullSize); + } + + void StorageAccessor::Range::Extract(std::string &target, + const std::string &source) const + { + SanityCheck(); + + if (hasStart_ && start_ >= source.size()) + { + throw OrthancException(ErrorCode_BadRange); + } + + if (hasEnd_ && end_ >= source.size()) + { + throw OrthancException(ErrorCode_BadRange); + } + + if (hasStart_ && hasEnd_) + { + target = source.substr(start_, end_ - start_ + 1); + } + else if (hasStart_) + { + target = source.substr(start_, source.size() - start_); + } + else if (hasEnd_) + { + target = source.substr(0, end_ + 1); + } + else + { + target = source; + } + } + + uint64_t StorageAccessor::Range::GetContentLength(uint64_t fullSize) const + { + SanityCheck(); + + if (fullSize == 0) + { + throw OrthancException(ErrorCode_BadRange); + } + + if (hasStart_ && start_ >= fullSize) + { + throw OrthancException(ErrorCode_BadRange); + } + + if (hasEnd_ && end_ >= fullSize) + { + throw OrthancException(ErrorCode_BadRange); + } + + if (hasStart_ && hasEnd_) + { + return end_ - start_ + 1; + } + else if (hasStart_) + { + return fullSize - start_; + } + else if (hasEnd_) + { + return end_ + 1; + } + else + { + return fullSize; + } + } + + StorageAccessor::Range StorageAccessor::Range::ParseHttpRange(const std::string& s) + { + static const std::string BYTES = "bytes="; + + if (!boost::starts_with(s, BYTES)) + { + throw OrthancException(ErrorCode_BadRange); // Range not satisfiable + } + + std::vector<std::string> tokens; + Orthanc::Toolbox::TokenizeString(tokens, s.substr(BYTES.length()), '-'); + + if (tokens.size() != 2) + { + throw OrthancException(ErrorCode_BadRange); + } + + Range range; + + uint64_t tmp; + if (!tokens[0].empty()) + { + if (SerializationToolbox::ParseUnsignedInteger64(tmp, tokens[0])) + { + range.SetStartInclusive(tmp); + } + } + + if (!tokens[1].empty()) + { + if (SerializationToolbox::ParseUnsignedInteger64(tmp, tokens[1])) + { + range.SetEndInclusive(tmp); + } + } + + range.SanityCheck(); + return range; + } + class StorageAccessor::MetricsTimer : public boost::noncopyable { private: @@ -432,15 +640,6 @@ } - void ReadStartRangeFromAreaInternal(std::string& target, - IStorageArea& area, - const std::string& fileUuid, - FileContentType contentType, - uint64_t end /* exclusive */) - { - - } - void StorageAccessor::ReadStartRange(std::string& target, const FileInfo& info, uint64_t end /* exclusive */) @@ -511,6 +710,79 @@ } + void StorageAccessor::ReadRange(std::string &target, + const FileInfo &info, + const Range &range, + bool uncompressIfNeeded) + { + if (uncompressIfNeeded && + info.GetCompressionType() != CompressionType_None) + { + // An uncompression is needed in this case + if (cache_ != NULL) + { + StorageCache::Accessor cacheAccessor(*cache_); + + std::string content; + if (cacheAccessor.Fetch(content, info.GetUuid(), info.GetContentType())) + { + range.Extract(target, content); + return; + } + } + + std::string content; + Read(content, info); + range.Extract(target, content); + } + else + { + // Access to the raw attachment is sufficient in this case + if (info.GetCompressionType() == CompressionType_None && + cache_ != NULL) + { + // Check out whether the raw attachment is already present in the cache, by chance + StorageCache::Accessor cacheAccessor(*cache_); + + std::string content; + if (cacheAccessor.Fetch(content, info.GetUuid(), info.GetContentType())) + { + range.Extract(target, content); + return; + } + } + + if (range.HasEnd() && + range.GetEndInclusive() >= info.GetCompressedSize()) + { + throw OrthancException(ErrorCode_BadRange); + } + + std::unique_ptr<IMemoryBuffer> buffer; + + if (range.HasStart() && + range.HasEnd()) + { + buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), range.GetStartInclusive(), range.GetEndInclusive() + 1, info.GetCustomData())); + } + else if (range.HasStart()) + { + buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), range.GetStartInclusive(), info.GetCompressedSize(), info.GetCustomData())); + } + else if (range.HasEnd()) + { + buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), 0, range.GetEndInclusive() + 1, info.GetCustomData())); + } + else + { + buffer.reset(area_.Read(info.GetUuid(), info.GetContentType(), info.GetCustomData())); + } + + buffer->MoveToString(target); + } + } + + #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 void StorageAccessor::SetupSender(BufferHttpSender& sender, const FileInfo& info,
--- a/OrthancFramework/Sources/FileStorage/StorageAccessor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageAccessor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -65,6 +65,48 @@ **/ class ORTHANC_PUBLIC StorageAccessor : boost::noncopyable { + public: + class ORTHANC_PUBLIC Range + { + private: + bool hasStart_; + uint64_t start_; + bool hasEnd_; + uint64_t end_; + + void SanityCheck() const; + + public: + Range(); + + void SetStartInclusive(uint64_t start); + + void SetEndInclusive(uint64_t end); + + bool HasStart() const + { + return hasStart_; + } + + bool HasEnd() const + { + return hasEnd_; + } + + uint64_t GetStartInclusive() const; + + uint64_t GetEndInclusive() const; + + std::string FormatHttpContentRange(uint64_t fullSize) const; + + void Extract(std::string& target, + const std::string& source) const; + + uint64_t GetContentLength(uint64_t fullSize) const; + + static Range ParseHttpRange(const std::string& s); + }; + private: class MetricsTimer; @@ -149,6 +191,11 @@ void Remove(const FileInfo& info); + void ReadRange(std::string& target, + const FileInfo& info, + const Range& range, + bool uncompressIfNeeded); + #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 void AnswerFile(HttpOutput& output, const FileInfo& info,
--- a/OrthancFramework/Sources/FileStorage/StorageCache.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageCache.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/FileStorage/StorageCache.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageCache.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpClient.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpClient.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -860,7 +860,18 @@ if (verifyPeers_) { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CAINFO, caCertificates_.c_str())); +#if defined(CURLSSLOPT_NATIVE_CA) // from curl v 8.2.0 + if (caCertificates_.empty()) // use native CA store (equivalent to --ca-native) + { + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA)); + } + else +#endif + { + // use provided CA file (equivalent to --cacert) + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CAINFO, caCertificates_.c_str())); + } + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYHOST, 2)); // libcurl default is strict verifyhost CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 1)); } @@ -1187,8 +1198,8 @@ { if (httpsVerifyCertificates.empty()) { - LOG(WARNING) << "No certificates are provided to validate peers, " - << "set \"HttpsCACertificates\" if you need to do HTTPS requests"; + LOG(WARNING) << "No certificates are provided to validate peers. Orthanc will use the native CA store. " + << "Set \"HttpsCACertificates\" if you need to do HTTPS requests and use custom CAs."; } else {
--- a/OrthancFramework/Sources/HttpClient.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpClient.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/BufferHttpSender.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/BufferHttpSender.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/BufferHttpSender.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/BufferHttpSender.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/CStringMatcher.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/CStringMatcher.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/CStringMatcher.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/CStringMatcher.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpContentNegociation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpContentNegociation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpContentNegociation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpContentNegociation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpFileSender.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpFileSender.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpFileSender.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpFileSender.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpOutput.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpOutput.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,7 +62,8 @@ contentPosition_(0), keepAlive_(isKeepAlive), keepAliveTimeout_(keepAliveTimeout), - hasXContentTypeOptions_(false) + hasXContentTypeOptions_(false), + hasContentType_(false) { } @@ -105,6 +106,7 @@ void HttpOutput::StateMachine::SetContentType(const char* contentType) { + hasContentType_ = true; AddHeader("Content-Type", contentType); } @@ -380,7 +382,8 @@ stateMachine_.SetHttpStatus(status); - if (messageSize > 0) + if (messageSize > 0 && + !stateMachine_.HasContentType()) { // Assume that the body always contains a textual description of the error stateMachine_.SetContentType("text/plain"); @@ -471,6 +474,10 @@ return stateMachine_.GetState() == StateMachine::State_WritingMultipart; } + bool HttpOutput::IsWritingStream() const + { + return stateMachine_.GetState() == StateMachine::State_WritingStream; + } void HttpOutput::Answer(const void* buffer, size_t length) @@ -974,4 +981,21 @@ stateMachine_.CloseStream(); } + + void HttpOutput::StartStream(const std::string& contentType) + { + stateMachine_.StartStream(contentType.c_str()); + } + + void HttpOutput::SendStreamItem(const void* data, + size_t size) + { + stateMachine_.SendStreamItem(data, size); + } + + void HttpOutput::CloseStream() + { + stateMachine_.CloseStream(); + } + }
--- a/OrthancFramework/Sources/HttpServer/HttpOutput.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpOutput.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +66,7 @@ unsigned int keepAliveTimeout_; std::list<std::string> headers_; bool hasXContentTypeOptions_; + bool hasContentType_; std::string multipartBoundary_; std::string multipartContentType_; @@ -125,6 +126,11 @@ size_t size); void CloseStream(); + + bool HasContentType() const + { + return hasContentType_; + } }; StateMachine stateMachine_; @@ -218,5 +224,14 @@ * used to handle compression using "Content-Encoding". **/ void AnswerWithoutBuffering(IHttpStreamAnswer& stream); + + void StartStream(const std::string& contentType); + + void SendStreamItem(const void* data, + size_t size); + + void CloseStream(); + + bool IsWritingStream() const; }; }
--- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpServer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpToolbox.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpToolbox.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/HttpToolbox.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpToolbox.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/IHttpHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/IHttpOutputStream.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpOutputStream.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/IHttpStreamAnswer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpStreamAnswer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/IWebDavBucket.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/IWebDavBucket.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/IWebDavBucket.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/IWebDavBucket.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/MultipartStreamReader.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/MultipartStreamReader.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/StringHttpOutput.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringHttpOutput.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/StringMatcher.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringMatcher.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/StringMatcher.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringMatcher.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/WebDavStorage.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/WebDavStorage.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/HttpServer/WebDavStorage.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/HttpServer/WebDavStorage.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/IDynamicObject.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/IDynamicObject.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/IMemoryBuffer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/IMemoryBuffer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/Font.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/Font.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/Font.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/Font.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/FontRegistry.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/FontRegistry.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/FontRegistry.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/FontRegistry.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/IImageWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/IImageWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/IImageWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/IImageWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/Image.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/Image.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/Image.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/Image.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/ImageAccessor.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/ImageAccessor.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -139,7 +139,7 @@ return pitch_; } - unsigned int ImageAccessor::GetSize() const + size_t ImageAccessor::GetSize() const { return GetHeight() * GetPitch(); } @@ -165,7 +165,7 @@ { if (buffer_ != NULL) { - return buffer_ + y * pitch_; + return buffer_ + static_cast<size_t>(y) * static_cast<size_t>(pitch_); } else { @@ -184,7 +184,7 @@ if (buffer_ != NULL) { - return buffer_ + y * pitch_; + return buffer_ + static_cast<size_t>(y) * static_cast<size_t>(pitch_); } else { @@ -325,8 +325,8 @@ else { uint8_t* p = (buffer_ + - y * pitch_ + - x * GetBytesPerPixel()); + static_cast<size_t>(y) * static_cast<size_t>(pitch_) + + static_cast<size_t>(x) * static_cast<size_t>(GetBytesPerPixel())); if (readOnly_) {
--- a/OrthancFramework/Sources/Images/ImageAccessor.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/ImageAccessor.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +86,7 @@ unsigned int GetPitch() const; - unsigned int GetSize() const; + size_t GetSize() const; const void* GetConstBuffer() const;
--- a/OrthancFramework/Sources/Images/ImageBuffer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/ImageBuffer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -47,7 +47,7 @@ */ pitch_ = GetBytesPerPixel() * width_; - size_t size = pitch_ * height_; + size_t size = static_cast<size_t>(pitch_) * static_cast<size_t>(height_); if (size == 0) {
--- a/OrthancFramework/Sources/Images/ImageBuffer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/ImageBuffer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/ImageProcessing.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/ImageProcessing.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -2888,8 +2888,7 @@ const unsigned int width = image.GetWidth(); const unsigned int height = image.GetHeight(); const unsigned int pitch = image.GetPitch(); - uint8_t* buffer = reinterpret_cast<uint8_t*>(image.GetBuffer()); - + if (image.GetFormat() != PixelFormat_RGB24 || pitch < 3 * width) { @@ -2898,7 +2897,7 @@ for (unsigned int y = 0; y < height; y++) { - uint8_t* p = buffer + y * pitch; + uint8_t* p = reinterpret_cast<uint8_t*>(image.GetRow(y)); for (unsigned int x = 0; x < width; x++, p += 3) {
--- a/OrthancFramework/Sources/Images/ImageProcessing.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/ImageProcessing.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/ImageTraits.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/ImageTraits.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/JpegErrorManager.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/JpegErrorManager.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/JpegErrorManager.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/JpegErrorManager.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/JpegReader.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/JpegReader.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/JpegReader.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/JpegReader.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/JpegWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/JpegWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/JpegWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/JpegWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/NumpyWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/NumpyWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/NumpyWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/NumpyWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PamReader.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PamReader.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PamReader.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PamReader.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PamWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PamWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PamWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PamWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PixelTraits.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PixelTraits.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PngReader.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PngReader.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PngReader.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PngReader.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PngWriter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PngWriter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Images/PngWriter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Images/PngWriter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/IJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/IJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,13 +49,18 @@ // For pausing/canceling/ending jobs: This method must release allocated resources virtual void Stop(JobStopReason reason) = 0; - virtual float GetProgress() = 0; + virtual float GetProgress() const = 0; - virtual void GetJobType(std::string& target) = 0; + virtual bool NeedsProgressUpdateBetweenSteps() const // only for jobs whose progress is updated by outside events (like C-Move and C-Get) + { + return false; + } + + virtual void GetJobType(std::string& target) const = 0; - virtual void GetPublicContent(Json::Value& value) = 0; + virtual void GetPublicContent(Json::Value& value) const = 0; - virtual bool Serialize(Json::Value& value) = 0; + virtual bool Serialize(Json::Value& value) const = 0; // This function can only be called if the job has reached its // "success" state
--- a/OrthancFramework/Sources/JobsEngine/IJobUnserializer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/IJobUnserializer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/JobInfo.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobInfo.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +54,8 @@ const JobStatus& status, const boost::posix_time::ptime& creationTime, const boost::posix_time::ptime& lastStateChangeTime, - const boost::posix_time::time_duration& runtime) : + const boost::posix_time::time_duration& runtime, + const IJob& job) : id_(id), priority_(priority), state_(state), @@ -68,11 +69,16 @@ if (state_ == JobState_Running) { float ms = static_cast<float>(runtime_.total_milliseconds()); + if (job.NeedsProgressUpdateBetweenSteps()) + { + status_.UpdateProgress(job); + } - if (status_.GetProgress() > 0.01f && + float progress = status_.GetProgress(); + + if (progress > 0.01f && ms > 0.01f) { - float progress = status_.GetProgress(); long long remaining = boost::math::llround(ms / progress * (1.0f - progress)); eta_ = timestamp_ + boost::posix_time::milliseconds(remaining); hasEta_ = true;
--- a/OrthancFramework/Sources/JobsEngine/JobInfo.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobInfo.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +51,8 @@ const JobStatus& status, const boost::posix_time::ptime& creationTime, const boost::posix_time::ptime& lastStateChangeTime, - const boost::posix_time::time_duration& runtime) ORTHANC_LOCAL; + const boost::posix_time::time_duration& runtime, + const IJob& job) ORTHANC_LOCAL; JobInfo();
--- a/OrthancFramework/Sources/JobsEngine/JobStatus.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStatus.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,7 +41,7 @@ JobStatus::JobStatus(ErrorCode code, const std::string& details, - IJob& job) : + const IJob& job) : errorCode_(code), progress_(job.GetProgress()), publicContent_(Json::objectValue),
--- a/OrthancFramework/Sources/JobsEngine/JobStatus.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStatus.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,7 +44,7 @@ JobStatus(ErrorCode code, const std::string& details, - IJob& job); + const IJob& job); ErrorCode GetErrorCode() const { @@ -61,6 +61,11 @@ return progress_; } + void UpdateProgress(const IJob& job) + { + progress_ = job.GetProgress(); + } + const std::string& GetJobType() const { return jobType_;
--- a/OrthancFramework/Sources/JobsEngine/JobStepResult.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStepResult.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/JobStepResult.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStepResult.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/JobsEngine.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsEngine.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -132,7 +132,10 @@ if (running.IsValid()) { - CLOG(INFO, JOBS) << "Executing job with priority " << running.GetPriority() + std::string jobType; + running.GetJob().GetJobType(jobType); + + CLOG(INFO, JOBS) << "Executing " << jobType << " job with priority " << running.GetPriority() << " in worker thread " << workerIndex << ": " << running.GetId(); while (engine->IsRunning())
--- a/OrthancFramework/Sources/JobsEngine/JobsEngine.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsEngine.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -223,8 +223,14 @@ lastStateChangeTime_ = time; } - const boost::posix_time::time_duration& GetRuntime() const + boost::posix_time::time_duration GetRuntime() const { + if (state_ == JobState_Running) + { + const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); + return now - lastStateChangeTime_; + } + return runtime_; } @@ -644,7 +650,8 @@ handler.GetLastStatus(), handler.GetCreationTime(), handler.GetLastStateChangeTime(), - handler.GetRuntime()); + handler.GetRuntime(), + handler.GetJob()); return true; } } @@ -792,7 +799,10 @@ } } - LOG(INFO) << "New job submitted with priority " << priority << ": " << id; + std::string jobType; + handler->GetJob().GetJobType(jobType); + + LOG(INFO) << "New " << jobType << " job submitted with priority " << priority << ": " << id; if (observer_ != NULL) {
--- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/IJobOperationValue.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/IJobOperationValue.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -398,7 +398,7 @@ } - float SequenceOfOperationsJob::GetProgress() + float SequenceOfOperationsJob::GetProgress() const { boost::mutex::scoped_lock lock(mutex_); @@ -406,13 +406,13 @@ static_cast<float>(operations_.size() + 1)); } - void SequenceOfOperationsJob::GetJobType(std::string& target) + void SequenceOfOperationsJob::GetJobType(std::string& target) const { target = "SequenceOfOperations"; } - void SequenceOfOperationsJob::GetPublicContent(Json::Value& value) + void SequenceOfOperationsJob::GetPublicContent(Json::Value& value) const { boost::mutex::scoped_lock lock(mutex_); @@ -421,7 +421,7 @@ } - bool SequenceOfOperationsJob::Serialize(Json::Value& value) + bool SequenceOfOperationsJob::Serialize(Json::Value& value) const { boost::mutex::scoped_lock lock(mutex_);
--- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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 +54,7 @@ std::string description_; bool done_; - boost::mutex mutex_; + mutable boost::mutex mutex_; std::vector<Operation*> operations_; size_t current_; boost::condition_variable operationAdded_; @@ -117,13 +117,13 @@ virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; - virtual float GetProgress() ORTHANC_OVERRIDE; + virtual float GetProgress() const ORTHANC_OVERRIDE; - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE; + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE; - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& value) const ORTHANC_OVERRIDE; virtual bool GetOutput(std::string& output, MimeType& mime,
--- a/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -137,7 +137,7 @@ } - float SetOfCommandsJob::GetProgress() + float SetOfCommandsJob::GetProgress() const { if (commands_.empty()) { @@ -237,13 +237,13 @@ static const char* KEY_COMMANDS = "Commands"; - void SetOfCommandsJob::GetPublicContent(Json::Value& value) + void SetOfCommandsJob::GetPublicContent(Json::Value& value) const { value[KEY_DESCRIPTION] = GetDescription(); } - bool SetOfCommandsJob::Serialize(Json::Value& target) + bool SetOfCommandsJob::Serialize(Json::Value& target) const { target = Json::objectValue;
--- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -92,7 +92,7 @@ virtual void Start() ORTHANC_OVERRIDE; - virtual float GetProgress() ORTHANC_OVERRIDE; + virtual float GetProgress() const ORTHANC_OVERRIDE; bool IsStarted() const; @@ -100,9 +100,9 @@ virtual JobStepResult Step(const std::string& jobId) ORTHANC_OVERRIDE; - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; virtual bool GetOutput(std::string& output, MimeType& mime,
--- a/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -209,7 +209,7 @@ static const char* KEY_FAILED_INSTANCES = "FailedInstances"; static const char* KEY_PARENT_RESOURCES = "ParentResources"; - void SetOfInstancesJob::GetPublicContent(Json::Value& target) + void SetOfInstancesJob::GetPublicContent(Json::Value& target) const { SetOfCommandsJob::GetPublicContent(target); target["InstancesCount"] = static_cast<uint32_t>(GetInstancesCount()); @@ -222,7 +222,7 @@ } - bool SetOfInstancesJob::Serialize(Json::Value& target) + bool SetOfInstancesJob::Serialize(Json::Value& target) const { if (SetOfCommandsJob::Serialize(target)) {
--- a/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -77,8 +77,8 @@ virtual void Reset() ORTHANC_OVERRIDE; - virtual void GetPublicContent(Json::Value& target) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& target) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; }; }
--- a/OrthancFramework/Sources/Logging.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Logging.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Logging.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Logging.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Lua/LuaContext.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Lua/LuaContext.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Lua/LuaContext.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Lua/LuaContext.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -124,5 +124,17 @@ lua_State* state, int top, bool keyToLowerCase); + +#if ORTHANC_ENABLE_CURL == 1 + void SetHttpsVerifyPeers(bool verify) + { + httpClient_.SetHttpsVerifyPeers(verify); + } + + bool IsHttpsVerifyPeers() const + { + return httpClient_.IsHttpsVerifyPeers(); + } +#endif }; }
--- a/OrthancFramework/Sources/Lua/LuaFunctionCall.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Lua/LuaFunctionCall.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Lua/LuaFunctionCall.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Lua/LuaFunctionCall.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MallocMemoryBuffer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MallocMemoryBuffer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MallocMemoryBuffer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MallocMemoryBuffer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MetricsRegistry.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MetricsRegistry.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MetricsRegistry.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MetricsRegistry.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/IRunnableBySteps.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/IRunnableBySteps.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/Mutex.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/Mutex.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/Semaphore.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/Semaphore.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/Semaphore.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/Semaphore.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/OrthancException.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/OrthancException.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/OrthancException.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/OrthancException.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/OrthancFramework.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/OrthancFramework.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/OrthancFramework.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/OrthancFramework.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Pkcs11.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Pkcs11.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Pkcs11.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Pkcs11.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/PrecompiledHeaders.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/PrecompiledHeaders.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/PrecompiledHeaders.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/PrecompiledHeaders.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApi.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApi.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApi.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApi.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiCall.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCall.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiCall.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCall.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiDeleteCall.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiDeleteCall.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiGetCall.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiGetCall.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiGetCall.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiGetCall.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiHierarchy.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiHierarchy.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiHierarchy.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiHierarchy.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiOutput.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiOutput.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiOutput.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiOutput.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiPath.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPath.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiPath.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPath.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiPostCall.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPostCall.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/RestApi/RestApiPutCall.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPutCall.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/SQLite/Connection.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/Connection.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/Connection.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/Connection.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/FunctionContext.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/FunctionContext.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -17,7 +17,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of the CHU of Liege, nor the names of its + * * Neither the name of the University Hospital of Liege, nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. *
--- a/OrthancFramework/Sources/SQLite/FunctionContext.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/FunctionContext.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -17,7 +17,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of the CHU of Liege, nor the names of its + * * Neither the name of the University Hospital of Liege, nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. *
--- a/OrthancFramework/Sources/SQLite/IScalarFunction.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/IScalarFunction.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -17,7 +17,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of the CHU of Liege, nor the names of its + * * Neither the name of the University Hospital of Liege, nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. *
--- a/OrthancFramework/Sources/SQLite/ITransaction.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/ITransaction.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/NonCopyable.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/NonCopyable.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -17,7 +17,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/OrthancSQLiteException.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/OrthancSQLiteException.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/SQLiteTypes.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/SQLiteTypes.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -17,7 +17,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of the CHU of Liege, nor the names of its + * * Neither the name of the University Hospital of Liege, nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. *
--- a/OrthancFramework/Sources/SQLite/Statement.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/Statement.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/Statement.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/Statement.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/StatementId.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementId.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/StatementId.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementId.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/StatementReference.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementReference.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/StatementReference.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementReference.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/Transaction.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/Transaction.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SQLite/Transaction.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SQLite/Transaction.h Thu Jan 30 17:41:33 2025 +0100 @@ -2,10 +2,10 @@ * Orthanc - A Lightweight, RESTful DICOM Store * * Copyright (C) 2012-2016 Sebastien Jodogne <s.jodogne@orthanc-labs.com>, - * Medical Physics Department, CHU of Liege, Belgium + * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -19,7 +19,7 @@ * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, + * * Neither the name of Google Inc., the name of the University Hospital of Liege, * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission.
--- a/OrthancFramework/Sources/SerializationToolbox.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SerializationToolbox.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/SerializationToolbox.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SerializationToolbox.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/SharedLibrary.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SharedLibrary.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/SharedLibrary.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SharedLibrary.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/StringMemoryBuffer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/StringMemoryBuffer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/StringMemoryBuffer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/StringMemoryBuffer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/SystemToolbox.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/SystemToolbox.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/TemporaryFile.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/TemporaryFile.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/TemporaryFile.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/TemporaryFile.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/Toolbox.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Toolbox.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -812,14 +812,32 @@ sha1.process_bytes(data, size); } +#if BOOST_VERSION >= 108600 + unsigned char digest[20]; + + // Sanity check for the memory layout: A SHA-1 digest is 160 bits wide + assert(sizeof(digest) == (160 / 8)); + assert(sizeof(boost::uuids::detail::sha1::digest_type) == 20); + + // 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(digest); + + result.resize(8 * 5 + 4); + sprintf(&result[0], "%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x%02x%02x", + digest[0], digest[1], digest[2], digest[3], + digest[4], digest[5], digest[6], digest[7], + digest[8], digest[9], digest[10], digest[11], + digest[12], digest[13], digest[14], digest[15], + digest[16], digest[17], digest[18], digest[19]); + +#else 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(boost::uuids::detail::sha1::digest_type) == 20); - - // 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<boost::uuids::detail::sha1::digest_type*>(digest))); + + sha1.get_digest(digest); result.resize(8 * 5 + 4); sprintf(&result[0], "%08x-%08x-%08x-%08x-%08x", @@ -828,6 +846,9 @@ digest[2], digest[3], digest[4]); + +#endif + } void Toolbox::ComputeSHA1(std::string& result,
--- a/OrthancFramework/Sources/Toolbox.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/Toolbox.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, 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,7 +262,7 @@ } } - // returns true if all element of 'needles' are found in 'haystack' + // returns the elements that are both in a and b template <typename T> static void GetIntersection(std::set<T>& target, const std::set<T>& a, const std::set<T>& b) { target.clear();
--- a/OrthancFramework/Sources/WebServiceParameters.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/WebServiceParameters.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/Sources/WebServiceParameters.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/Sources/WebServiceParameters.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -806,6 +806,7 @@ dicom.ReplacePlainString(DICOM_TAG_PATIENT_NAME, "SB1^SB2^SB3^SB4^SB5"); dicom.ReplacePlainString(DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "1\\2.3\\4"); dicom.ReplacePlainString(DICOM_TAG_IMAGE_POSITION_PATIENT, ""); + dicom.ReplacePlainString(DICOM_TAG_PIXEL_SPACING, "0,143\\0,143"); // seen in https://discourse.orthanc-server.org/t/dicomwebplugin-does-not-return-series-metadata-properly/5195 DicomWebJsonVisitor visitor; dicom.Apply(visitor); @@ -817,10 +818,10 @@ ASSERT_EQ(EnumerationToString(ValueRepresentation_DecimalString), tag["vr"].asString()); ASSERT_EQ(2u, tag.getMemberNames().size()); ASSERT_EQ(3u, value.size()); - ASSERT_EQ(Json::realValue, value[1].type()); - ASSERT_FLOAT_EQ(1.0f, value[0].asFloat()); - ASSERT_FLOAT_EQ(2.3f, value[1].asFloat()); - ASSERT_FLOAT_EQ(4.0f, value[2].asFloat()); + ASSERT_EQ(Json::stringValue, value[1].type()); // since Orthanc 1.12.5, this is now stored as a string + ASSERT_EQ("1", value[0].asString()); + ASSERT_EQ("2.3", value[1].asString()); + ASSERT_EQ("4", value[2].asString()); } { @@ -829,13 +830,23 @@ ASSERT_EQ(1u, tag.getMemberNames().size()); } + { + const Json::Value& tag = visitor.GetResult() ["00280030"]; // PixelSpacing + const Json::Value& value = tag["Value"]; + + ASSERT_EQ(EnumerationToString(ValueRepresentation_DecimalString), tag["vr"].asString()); + ASSERT_EQ(2u, value.size()); + ASSERT_EQ("0.143", value[0].asString()); + ASSERT_EQ("0.143", value[1].asString()); + } + std::string xml; visitor.FormatXml(xml); { DicomMap m; m.FromDicomWeb(visitor.GetResult()); - ASSERT_EQ(3u, m.GetSize()); + ASSERT_EQ(4u, m.GetSize()); std::string s; ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false)); @@ -871,12 +882,12 @@ ASSERT_EQ(EnumerationToString(ValueRepresentation_DecimalString), tag["vr"].asString()); ASSERT_EQ(2u, tag.getMemberNames().size()); ASSERT_EQ(4u, value.size()); - ASSERT_EQ(Json::realValue, value[0].type()); + ASSERT_EQ(Json::stringValue, value[0].type()); ASSERT_EQ(Json::nullValue, value[1].type()); ASSERT_EQ(Json::nullValue, value[2].type()); - ASSERT_EQ(Json::realValue, value[3].type()); - ASSERT_FLOAT_EQ(1.5f, value[0].asFloat()); - ASSERT_FLOAT_EQ(2.5f, value[3].asFloat()); + ASSERT_EQ(Json::stringValue, value[3].type()); + ASSERT_EQ("1.5", value[0].asString()); + ASSERT_EQ("2.5", value[3].asString()); } std::string xml; @@ -914,8 +925,8 @@ target.FromDicomWeb(visitor.GetResult()); ASSERT_EQ("DS", visitor.GetResult() ["00280030"]["vr"].asString()); - ASSERT_FLOAT_EQ(1.5f, visitor.GetResult() ["00280030"]["Value"][0].asFloat()); - ASSERT_FLOAT_EQ(1.3f, visitor.GetResult() ["00280030"]["Value"][1].asFloat()); + ASSERT_EQ("1.5", visitor.GetResult() ["00280030"]["Value"][0].asString()); + ASSERT_EQ("1.3", visitor.GetResult() ["00280030"]["Value"][1].asString()); std::string s; ASSERT_TRUE(target.LookupStringValue(s, DICOM_TAG_PIXEL_SPACING, false));
--- a/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -239,3 +239,92 @@ ASSERT_THROW(accessor.Read(r, uncompressedInfo.GetUuid(), FileContentType_Unknown), OrthancException); */ } + + +TEST(StorageAccessor, Range) +{ + { + StorageAccessor::Range range; + ASSERT_FALSE(range.HasStart()); + ASSERT_FALSE(range.HasEnd()); + ASSERT_THROW(range.GetStartInclusive(), OrthancException); + ASSERT_THROW(range.GetEndInclusive(), OrthancException); + ASSERT_EQ("bytes 0-99/100", range.FormatHttpContentRange(100)); + ASSERT_EQ("bytes 0-0/1", range.FormatHttpContentRange(1)); + ASSERT_THROW(range.FormatHttpContentRange(0), OrthancException); + ASSERT_EQ(100u, range.GetContentLength(100)); + ASSERT_EQ(1u, range.GetContentLength(1)); + ASSERT_THROW(range.GetContentLength(0), OrthancException); + + range.SetStartInclusive(10); + ASSERT_TRUE(range.HasStart()); + ASSERT_FALSE(range.HasEnd()); + ASSERT_EQ(10u, range.GetStartInclusive()); + ASSERT_THROW(range.GetEndInclusive(), OrthancException); + ASSERT_EQ("bytes 10-99/100", range.FormatHttpContentRange(100)); + ASSERT_EQ("bytes 10-10/11", range.FormatHttpContentRange(11)); + ASSERT_THROW(range.FormatHttpContentRange(10), OrthancException); + ASSERT_EQ(90u, range.GetContentLength(100)); + ASSERT_EQ(1u, range.GetContentLength(11)); + ASSERT_THROW(range.GetContentLength(10), OrthancException); + + range.SetEndInclusive(30); + ASSERT_TRUE(range.HasStart()); + ASSERT_TRUE(range.HasEnd()); + ASSERT_EQ(10u, range.GetStartInclusive()); + ASSERT_EQ(30u, range.GetEndInclusive()); + ASSERT_EQ("bytes 10-30/100", range.FormatHttpContentRange(100)); + ASSERT_EQ("bytes 10-30/31", range.FormatHttpContentRange(31)); + ASSERT_THROW(range.FormatHttpContentRange(30), OrthancException); + ASSERT_EQ(21u, range.GetContentLength(100)); + ASSERT_EQ(21u, range.GetContentLength(31)); + ASSERT_THROW(range.GetContentLength(30), OrthancException); + } + + { + StorageAccessor::Range range; + range.SetEndInclusive(20); + ASSERT_FALSE(range.HasStart()); + ASSERT_TRUE(range.HasEnd()); + ASSERT_THROW(range.GetStartInclusive(), OrthancException); + ASSERT_EQ(20u, range.GetEndInclusive()); + ASSERT_EQ("bytes 0-20/100", range.FormatHttpContentRange(100)); + ASSERT_EQ("bytes 0-20/21", range.FormatHttpContentRange(21)); + ASSERT_THROW(range.FormatHttpContentRange(20), OrthancException); + ASSERT_EQ(21u, range.GetContentLength(100)); + ASSERT_EQ(21u, range.GetContentLength(21)); + ASSERT_THROW(range.GetContentLength(20), OrthancException); + } + + { + StorageAccessor::Range range = StorageAccessor::Range::ParseHttpRange("bytes=1-30"); + ASSERT_TRUE(range.HasStart()); + ASSERT_TRUE(range.HasEnd()); + ASSERT_EQ(1u, range.GetStartInclusive()); + ASSERT_EQ(30u, range.GetEndInclusive()); + ASSERT_EQ("bytes 1-30/100", range.FormatHttpContentRange(100)); + } + + ASSERT_THROW(StorageAccessor::Range::ParseHttpRange("bytes="), OrthancException); + ASSERT_THROW(StorageAccessor::Range::ParseHttpRange("bytes=-1-30"), OrthancException); + ASSERT_THROW(StorageAccessor::Range::ParseHttpRange("bytes=100-30"), OrthancException); + + ASSERT_EQ("bytes 0-99/100", StorageAccessor::Range::ParseHttpRange("bytes=-").FormatHttpContentRange(100)); + ASSERT_EQ("bytes 0-10/100", StorageAccessor::Range::ParseHttpRange("bytes=-10").FormatHttpContentRange(100)); + ASSERT_EQ("bytes 10-99/100", StorageAccessor::Range::ParseHttpRange("bytes=10-").FormatHttpContentRange(100)); + + { + std::string s; + StorageAccessor::Range::ParseHttpRange("bytes=1-2").Extract(s, "Hello"); + ASSERT_EQ("el", s); + StorageAccessor::Range::ParseHttpRange("bytes=-2").Extract(s, "Hello"); + ASSERT_EQ("Hel", s); + StorageAccessor::Range::ParseHttpRange("bytes=3-").Extract(s, "Hello"); + ASSERT_EQ("lo", s); + StorageAccessor::Range::ParseHttpRange("bytes=-").Extract(s, "Hello"); + ASSERT_EQ("Hello", s); + StorageAccessor::Range::ParseHttpRange("bytes=4-").Extract(s, "Hello"); + ASSERT_EQ("o", s); + ASSERT_THROW(StorageAccessor::Range::ParseHttpRange("bytes=5-").Extract(s, "Hello"), OrthancException); + } +} \ No newline at end of file
--- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -2043,7 +2043,7 @@ ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["vr"].asString()); ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["Value"][0].asString()); ASSERT_EQ("DS", visitor.GetResult() ["00101020"]["vr"].asString()); - ASSERT_FLOAT_EQ(42.0f, visitor.GetResult() ["00101020"]["Value"][0].asFloat()); + ASSERT_EQ("42", visitor.GetResult() ["00101020"]["Value"][0].asString()); ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["vr"].asString()); ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["Value"][0].asString()); ASSERT_EQ("FL", visitor.GetResult() ["00109431"]["vr"].asString()); @@ -3561,7 +3561,7 @@ scu.SetCommonClassesProposed(false); scu.SetRetiredBigEndianProposed(true); - DcmtkTranscoder transcoder; + DcmtkTranscoder transcoder(1); for (int j = 0; j < 2; j++) { @@ -3618,7 +3618,7 @@ DicomTransferSyntax sourceSyntax; ASSERT_TRUE(FromDcmtkBridge::LookupOrthancTransferSyntax(sourceSyntax, *toto)); - DcmtkTranscoder transcoder; + DcmtkTranscoder transcoder(1); for (int i = 0; i <= DicomTransferSyntax_XML; i++) {
--- a/OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/ImageTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/ImageTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/JobsTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -103,24 +103,24 @@ { } - virtual float GetProgress() ORTHANC_OVERRIDE + virtual float GetProgress() const ORTHANC_OVERRIDE { return static_cast<float>(count_) / static_cast<float>(steps_ - 1); } - virtual void GetJobType(std::string& type) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& type) const ORTHANC_OVERRIDE { type = "DummyJob"; } - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE + virtual bool Serialize(Json::Value& value) const ORTHANC_OVERRIDE { value = Json::objectValue; value["Type"] = "DummyJob"; return true; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE { value["hello"] = "world"; } @@ -199,7 +199,7 @@ { } - virtual void GetJobType(std::string& s) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& s) const ORTHANC_OVERRIDE { s = "DummyInstancesJob"; } @@ -783,7 +783,7 @@ static bool CheckIdempotentSerialization(IJobUnserializer& unserializer, - IJob& job) + const IJob& job) { Json::Value a = 42; @@ -809,7 +809,7 @@ static bool CheckIdempotentSetOfInstances(IJobUnserializer& unserializer, - SetOfInstancesJob& job) + const SetOfInstancesJob& job) { Json::Value a = 42;
--- a/OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/LoggingTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/LoggingTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/LuaTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/LuaTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/RestApiTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/RestApiTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -73,19 +73,24 @@ ASSERT_TRUE(c.IsVerbose()); c.SetVerbose(false); ASSERT_FALSE(c.IsVerbose()); + ASSERT_TRUE(c.IsRedirectionFollowed()); + c.SetRedirectionFollowed(false); + ASSERT_FALSE(c.IsRedirectionFollowed()); #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 - // The "http://www.orthanc-server.com/downloads/third-party/" does - // not automatically redirect to HTTPS, so we cas use it even if the - // OpenSSL/HTTPS support is disabled in curl - const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/"; + // The "http://httpbin.org/get" URL does not automatically redirect + // to HTTPS, so we can use it even if the OpenSSL/HTTPS support is + // disabled in curl + const std::string URL = "http://httpbin.org/get"; + Json::Value v; - c.SetUrl(BASE + "Product.json"); + c.SetUrl(URL); c.Apply(v); ASSERT_TRUE(v.type() == Json::objectValue); - ASSERT_TRUE(v.isMember("Description")); + ASSERT_TRUE(v.isMember("url")); + ASSERT_EQ(URL, v["url"].asString()); #endif } #endif
--- a/OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/SQLiteTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/SQLiteTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/SharedLibraryUnitTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/SharedLibraryUnitTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/StreamTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/StreamTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/ToolboxTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/ToolboxTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancFramework/UnitTestsSources/ZipTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancFramework/UnitTestsSources/ZipTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License
--- a/OrthancServer/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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 @@ -89,7 +89,7 @@ ##################################################################### set(ORTHANC_SERVER_SOURCES - ${CMAKE_SOURCE_DIR}/Sources/Database/BaseDatabaseWrapper.cpp + ${CMAKE_SOURCE_DIR}/Sources/Database/BaseCompatibilityTransaction.cpp ${CMAKE_SOURCE_DIR}/Sources/Database/Compatibility/DatabaseLookup.cpp ${CMAKE_SOURCE_DIR}/Sources/Database/Compatibility/GenericFind.cpp ${CMAKE_SOURCE_DIR}/Sources/Database/Compatibility/ICreateInstance.cpp @@ -139,6 +139,8 @@ ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/ArchiveJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/CleaningInstancesJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/DicomModalityStoreJob.cpp + ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/DicomRetrieveScuBaseJob.cpp + ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/DicomGetScuJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/DicomMoveScuJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/LuaJobManager.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/MergeStudyJob.cpp @@ -155,6 +157,7 @@ ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/StorageCommitmentScpJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/ThreadedSetOfInstancesJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerToolbox.cpp + ${CMAKE_SOURCE_DIR}/Sources/SimpleInstanceOrdering.cpp ${CMAKE_SOURCE_DIR}/Sources/SliceOrdering.cpp ${CMAKE_SOURCE_DIR}/Sources/StorageCommitmentReports.cpp ) @@ -184,6 +187,7 @@ ${CMAKE_SOURCE_DIR}/UnitTestsSources/DatabaseLookupTests.cpp ${CMAKE_SOURCE_DIR}/UnitTestsSources/LuaServerTests.cpp ${CMAKE_SOURCE_DIR}/UnitTestsSources/PluginsTests.cpp + ${CMAKE_SOURCE_DIR}/UnitTestsSources/ServerConfigTests.cpp ${CMAKE_SOURCE_DIR}/UnitTestsSources/ServerIndexTests.cpp ${CMAKE_SOURCE_DIR}/UnitTestsSources/ServerJobsTests.cpp ${CMAKE_SOURCE_DIR}/UnitTestsSources/SizeOfTests.cpp
--- a/OrthancServer/OrthancExplorer/explorer.css Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/OrthancExplorer/explorer.css Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/OrthancExplorer/explorer.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/OrthancExplorer/explorer.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/OrthancExplorer/file-upload.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/OrthancExplorer/file-upload.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/OrthancExplorer/query-retrieve.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/OrthancExplorer/query-retrieve.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -341,9 +341,9 @@ success: function(system) { $('#retrieve-target').val(system['DicomAet']); + $('#retrieve-form').unbind('submit'); $('#retrieve-form').submit(function(event) { var aet; - event.preventDefault(); aet = $('#retrieve-target').val();
--- a/OrthancServer/Plugins/Engine/IPluginServiceProvider.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/IPluginServiceProvider.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -44,7 +44,7 @@ namespace Orthanc { class OrthancPluginDatabase::Transaction : - public BaseDatabaseWrapper::BaseTransaction, + public BaseCompatibilityTransaction, public Compatibility::ICreateInstance, public Compatibility::IGetChildrenMetadata, public Compatibility::ILookupResources, @@ -808,10 +808,10 @@ } - virtual void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - int64_t since, - uint32_t limit) ORTHANC_OVERRIDE + virtual void GetAllPublicIdsCompatibility(std::list<std::string>& target, + ResourceType resourceType, + int64_t since, + uint32_t limit) ORTHANC_OVERRIDE { if (that_.extensions_.getAllPublicIdsWithLimit != NULL) { @@ -1662,4 +1662,9 @@ LOG(WARNING) << "Received an answer from the database index plugin, but not transaction is active"; } } + + uint64_t OrthancPluginDatabase::MeasureLatency() + { + throw OrthancException(ErrorCode_NotImplemented); + } }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -26,7 +26,7 @@ #if ORTHANC_ENABLE_PLUGINS == 1 #include "../../../OrthancFramework/Sources/SharedLibrary.h" -#include "../../Sources/Database/BaseDatabaseWrapper.h" +#include "../../Sources/Database/BaseCompatibilityTransaction.h" #include "../Include/orthanc/OrthancCDatabasePlugin.h" #include "PluginsErrorDictionary.h" @@ -46,7 +46,7 @@ * able to rollback the modifications. Read-only accesses didn't * start a transaction, as they were protected by the global mutex. **/ - class OrthancPluginDatabase : public BaseDatabaseWrapper + class OrthancPluginDatabase : public IDatabaseWrapper { private: class Transaction; @@ -111,6 +111,13 @@ } void AnswerReceived(const _OrthancPluginDatabaseAnswer& answer); + + uint64_t MeasureLatency() ORTHANC_OVERRIDE; + + bool HasIntegratedFind() const ORTHANC_OVERRIDE + { + return false; + } }; }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -46,7 +46,7 @@ namespace Orthanc { - class OrthancPluginDatabaseV3::Transaction : public BaseDatabaseWrapper::BaseTransaction + class OrthancPluginDatabaseV3::Transaction : public BaseCompatibilityTransaction { private: OrthancPluginDatabaseV3& that_; @@ -388,10 +388,10 @@ } - virtual void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - int64_t since, - uint32_t limit) ORTHANC_OVERRIDE + virtual void GetAllPublicIdsCompatibility(std::list<std::string>& target, + ResourceType resourceType, + int64_t since, + uint32_t limit) ORTHANC_OVERRIDE { CheckSuccess(that_.backend_.getAllPublicIdsWithLimit( transaction_, Plugins::Convert(resourceType), @@ -1258,4 +1258,9 @@ } } + uint64_t OrthancPluginDatabaseV3::MeasureLatency() + { + throw OrthancException(ErrorCode_NotImplemented); + } + }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -26,13 +26,13 @@ #if ORTHANC_ENABLE_PLUGINS == 1 #include "../../../OrthancFramework/Sources/SharedLibrary.h" -#include "../../Sources/Database/BaseDatabaseWrapper.h" +#include "../../Sources/Database/BaseCompatibilityTransaction.h" #include "../Include/orthanc/OrthancCDatabasePlugin.h" #include "PluginsErrorDictionary.h" namespace Orthanc { - class OrthancPluginDatabaseV3 : public BaseDatabaseWrapper + class OrthancPluginDatabaseV3 : public IDatabaseWrapper { private: class Transaction; @@ -82,6 +82,13 @@ { return dbCapabilities_; } + + uint64_t MeasureLatency() ORTHANC_OVERRIDE; + + bool HasIntegratedFind() const ORTHANC_OVERRIDE + { + return false; + } }; }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -267,6 +267,24 @@ default: throw OrthancException(ErrorCode_ParameterOutOfRange); } + + switch (source.GetCast()) + { + case FindRequest::OrderingCast_Int: + target.set_cast(DatabasePluginMessages::ORDERING_CAST_INT); + break; + + case FindRequest::OrderingCast_Float: + target.set_cast(DatabasePluginMessages::ORDERING_CAST_FLOAT); + break; + + case FindRequest::OrderingCast_String: + target.set_cast(DatabasePluginMessages::ORDERING_CAST_STRING); + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } } static DatabasePluginMessages::LabelsConstraintType Convert(LabelsConstraint constraint) @@ -292,6 +310,7 @@ const FindRequest::ChildrenSpecification& source) { target.set_retrieve_identifiers(source.IsRetrieveIdentifiers()); + target.set_retrieve_count(source.IsRetrieveCount()); for (std::set<MetadataType>::const_iterator it = source.GetMetadata().begin(); it != source.GetMetadata().end(); ++it) { @@ -319,7 +338,8 @@ for (int i = 0; i < source.metadata().size(); i++) { - target.AddMetadata(level, static_cast<MetadataType>(source.metadata(i).key()), source.metadata(i).value()); + target.AddMetadata(level, static_cast<MetadataType>(source.metadata(i).key()), + source.metadata(i).value(), source.metadata(i).revision()); } } @@ -333,24 +353,18 @@ target.AddChildIdentifier(level, source.identifiers(i)); } + target.SetChildrenCount(level, source.count()); + for (int i = 0; i < source.main_dicom_tags().size(); i++) { const DicomTag tag(source.main_dicom_tags(i).group(), source.main_dicom_tags(i).element()); - - for (int j = 0; j < source.main_dicom_tags(i).values().size(); j++) - { - target.AddChildrenMainDicomTagValue(level, tag, source.main_dicom_tags(i).values(j)); - } + target.AddChildrenMainDicomTagValue(level, tag, source.main_dicom_tags(i).value()); } for (int i = 0; i < source.metadata().size(); i++) { MetadataType key = static_cast<MetadataType>(source.metadata(i).key()); - - for (int j = 0; j < source.metadata(i).values().size(); j++) - { - target.AddChildrenMetadataValue(level, key, source.metadata(i).values(j)); - } + target.AddChildrenMetadataValue(level, key, source.metadata(i).value()); } } @@ -399,7 +413,9 @@ } - class OrthancPluginDatabaseV4::Transaction : public IDatabaseWrapper::ITransaction + class OrthancPluginDatabaseV4::Transaction : + public IDatabaseWrapper::ITransaction, + public IDatabaseWrapper::ICompatibilityTransaction { private: OrthancPluginDatabaseV4& database_; @@ -561,7 +577,7 @@ request.mutable_add_attachment()->mutable_attachment()->set_compression_type(attachment.GetCompressionType()); request.mutable_add_attachment()->mutable_attachment()->set_compressed_size(attachment.GetCompressedSize()); request.mutable_add_attachment()->mutable_attachment()->set_compressed_hash(attachment.GetCompressedMD5()); - request.mutable_add_attachment()->mutable_attachment()->set_custom_data(attachment.GetCustomData()); // new in 1.12.6 + request.mutable_add_attachment()->mutable_attachment()->set_custom_data(attachment.GetCustomData()); // new in 1.12.7 request.mutable_add_attachment()->set_revision(revision); ExecuteTransaction(DatabasePluginMessages::OPERATION_ADD_ATTACHMENT, request); @@ -675,10 +691,10 @@ } - virtual void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - int64_t since, - uint32_t limit) ORTHANC_OVERRIDE + virtual void GetAllPublicIdsCompatibility(std::list<std::string>& target, + ResourceType resourceType, + int64_t since, + uint32_t limit) ORTHANC_OVERRIDE { DatabasePluginMessages::TransactionRequest request; request.mutable_get_all_public_ids_with_limits()->set_resource_type(Convert(resourceType)); @@ -1477,6 +1493,63 @@ } + virtual void ExecuteCount(uint64_t& count, + const FindRequest& request, + const Capabilities& capabilities) ORTHANC_OVERRIDE + { + if (capabilities.HasFindSupport()) + { + DatabasePluginMessages::TransactionRequest dbRequest; + dbRequest.mutable_find()->set_level(Convert(request.GetLevel())); + + if (request.GetOrthancIdentifiers().HasPatientId()) + { + dbRequest.mutable_find()->set_orthanc_id_patient(request.GetOrthancIdentifiers().GetPatientId()); + } + + if (request.GetOrthancIdentifiers().HasStudyId()) + { + dbRequest.mutable_find()->set_orthanc_id_study(request.GetOrthancIdentifiers().GetStudyId()); + } + + if (request.GetOrthancIdentifiers().HasSeriesId()) + { + dbRequest.mutable_find()->set_orthanc_id_series(request.GetOrthancIdentifiers().GetSeriesId()); + } + + if (request.GetOrthancIdentifiers().HasInstanceId()) + { + dbRequest.mutable_find()->set_orthanc_id_instance(request.GetOrthancIdentifiers().GetInstanceId()); + } + + for (size_t i = 0; i < request.GetDicomTagConstraints().GetSize(); i++) + { + Convert(*dbRequest.mutable_find()->add_dicom_tag_constraints(), request.GetDicomTagConstraints().GetConstraint(i)); + } + + for (std::deque<DatabaseMetadataConstraint*>::const_iterator it = request.GetMetadataConstraint().begin(); it != request.GetMetadataConstraint().end(); ++it) + { + Convert(*dbRequest.mutable_find()->add_metadata_constraints(), *(*it)); + } + + for (std::set<std::string>::const_iterator it = request.GetLabels().begin(); it != request.GetLabels().end(); ++it) + { + dbRequest.mutable_find()->add_labels(*it); + } + + dbRequest.mutable_find()->set_labels_constraint(Convert(request.GetLabelsConstraint())); + + DatabasePluginMessages::TransactionResponse dbResponse; + ExecuteTransaction(dbResponse, DatabasePluginMessages::OPERATION_COUNT_RESOURCES, dbRequest); + + count = dbResponse.count_resources().count(); + } + else + { + throw OrthancException(ErrorCode_NotImplemented); + } + } + virtual void ExecuteFind(FindResponse& response, const FindRequest& request, const Capabilities& capabilities) ORTHANC_OVERRIDE @@ -1603,14 +1676,19 @@ target->SetParentIdentifier(source.parent_public_id()); } - for (int i = 0; i < source.labels().size(); i++) + for (int j = 0; j < source.labels().size(); j++) { - target->AddLabel(source.labels(i)); + target->AddLabel(source.labels(j)); } - for (int i = 0; i < source.attachments().size(); i++) + if (source.attachments().size() != source.attachments_revisions().size()) { - target->AddAttachment(Convert(source.attachments(i))); + throw OrthancException(ErrorCode_DatabasePlugin); + } + + for (int j = 0; j < source.attachments().size(); j++) + { + target->AddAttachment(Convert(source.attachments(j)), source.attachments_revisions(j)); } Convert(*target, ResourceType_Patient, source.patient_content()); @@ -1655,12 +1733,12 @@ request.IsRetrieveOneInstanceMetadataAndAttachments()) { std::map<MetadataType, std::string> metadata; - for (int i = 0; i < source.one_instance_metadata().size(); i++) + for (int j = 0; j < source.one_instance_metadata().size(); j++) { - MetadataType key = static_cast<MetadataType>(source.one_instance_metadata(i).key()); + MetadataType key = static_cast<MetadataType>(source.one_instance_metadata(j).key()); if (metadata.find(key) == metadata.end()) { - metadata[key] = source.one_instance_metadata(i).value(); + metadata[key] = source.one_instance_metadata(j).value(); } else { @@ -1670,9 +1748,9 @@ std::map<FileContentType, FileInfo> attachments; - for (int i = 0; i < source.one_instance_attachments().size(); i++) + for (int j = 0; j < source.one_instance_attachments().size(); j++) { - FileInfo info(Convert(source.one_instance_attachments(i))); + FileInfo info(Convert(source.one_instance_attachments(j))); if (attachments.find(info.GetContentType()) == attachments.end()) { attachments[info.GetContentType()] = info; @@ -1707,7 +1785,7 @@ } else { - Compatibility::GenericFind find(*this); + Compatibility::GenericFind find(*this, *this); find.ExecuteFind(identifiers, capabilities, request); } } @@ -1725,7 +1803,7 @@ } else { - Compatibility::GenericFind find(*this); + Compatibility::GenericFind find(*this, *this); find.ExecuteExpand(response, capabilities, request, identifier); } } @@ -1815,7 +1893,7 @@ dbCapabilities_.SetRevisionsSupport(systemInfo.supports_revisions()); dbCapabilities_.SetLabelsSupport(systemInfo.supports_labels()); dbCapabilities_.SetAtomicIncrementGlobalProperty(systemInfo.supports_increment_global_property()); - dbCapabilities_.SetUpdateAndGetStatistics(systemInfo.has_update_and_get_statistics()); + dbCapabilities_.SetHasUpdateAndGetStatistics(systemInfo.has_update_and_get_statistics()); dbCapabilities_.SetMeasureLatency(systemInfo.has_measure_latency()); dbCapabilities_.SetHasExtendedChanges(systemInfo.has_extended_changes()); dbCapabilities_.SetHasFindSupport(systemInfo.supports_find());
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -1471,40 +1471,41 @@ class PluginHttpOutput : public boost::noncopyable { private: - enum MultipartState - { - MultipartState_None, - MultipartState_FirstPart, - MultipartState_SecondPart, - MultipartState_NextParts + enum State + { + State_None, + State_MultipartFirstPart, + State_MultipartSecondPart, + State_MultipartNextParts, + State_WritingStream }; HttpOutput& output_; std::unique_ptr<std::string> errorDetails_; bool logDetails_; - MultipartState multipartState_; + State state_; std::string multipartSubType_; std::string multipartContentType_; std::string multipartFirstPart_; std::map<std::string, std::string> multipartFirstHeaders_; - + public: explicit PluginHttpOutput(HttpOutput& output) : output_(output), logDetails_(false), - multipartState_(MultipartState_None) + state_(State_None) { } HttpOutput& GetOutput() { - if (multipartState_ == MultipartState_None) + if (state_ == State_None) { return output_; } else { - // Must use "SendMultipartItem()" on multipart streams + // Must use "SendMultipartItem()" on multipart streams or "SendStreamChunk()" throw OrthancException(ErrorCode_BadSequenceOfCalls); } } @@ -1541,17 +1542,44 @@ void StartMultipart(const char* subType, const char* contentType) { - if (multipartState_ != MultipartState_None) + if (state_ != State_None) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + state_ = State_MultipartFirstPart; + multipartSubType_ = subType; + multipartContentType_ = contentType; + } + } + + void StartStream(const char* contentType) + { + if (state_ != State_None) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } else { - multipartState_ = MultipartState_FirstPart; - multipartSubType_ = subType; - multipartContentType_ = contentType; - } - } + output_.StartStream(contentType); + state_ = State_WritingStream; + } + } + + void SendStreamItem(const void* data, + size_t size) + { + if (state_ != State_WritingStream) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + output_.SendStreamItem(data, size); + } + } + void SendMultipartItem(const void* data, size_t size, @@ -1562,19 +1590,19 @@ throw OrthancException(ErrorCode_NullPointer); } - switch (multipartState_) - { - case MultipartState_None: + switch (state_) + { + case State_None: // Must call "StartMultipart()" before throw OrthancException(ErrorCode_BadSequenceOfCalls); - case MultipartState_FirstPart: + case State_MultipartFirstPart: multipartFirstPart_.assign(reinterpret_cast<const char*>(data), size); multipartFirstHeaders_ = headers; - multipartState_ = MultipartState_SecondPart; + state_ = State_MultipartSecondPart; break; - case MultipartState_SecondPart: + case State_MultipartSecondPart: // Start an actual stream for chunked transfer as soon as // there are more than 2 elements in the multipart stream output_.StartMultipart(multipartSubType_, multipartContentType_); @@ -1583,10 +1611,10 @@ multipartFirstPart_.clear(); // Release memory output_.SendMultipartItem(data, size, headers); - multipartState_ = MultipartState_NextParts; + state_ = State_MultipartNextParts; break; - case MultipartState_NextParts: + case State_MultipartNextParts: output_.SendMultipartItem(data, size, headers); break; @@ -1600,21 +1628,21 @@ { if (error == OrthancPluginErrorCode_Success) { - switch (multipartState_) + switch (state_) { - case MultipartState_None: + case State_None: assert(!output_.IsWritingMultipart()); break; - case MultipartState_FirstPart: // Multipart started, but no part was sent - case MultipartState_SecondPart: // Multipart started, first part is pending + case State_MultipartFirstPart: // Multipart started, but no part was sent + case State_MultipartSecondPart: // Multipart started, first part is pending { assert(!output_.IsWritingMultipart()); std::vector<const void*> parts; std::vector<size_t> sizes; std::vector<const std::map<std::string, std::string>*> headers; - if (multipartState_ == MultipartState_SecondPart) + if (state_ == State_MultipartSecondPart) { parts.push_back(multipartFirstPart_.c_str()); sizes.push_back(multipartFirstPart_.size()); @@ -1626,9 +1654,15 @@ break; } - case MultipartState_NextParts: + case State_MultipartNextParts: assert(output_.IsWritingMultipart()); output_.CloseMultipart(); + break; + + case State_WritingStream: + assert(output_.IsWritingStream()); + output_.CloseStream(); + break; default: throw OrthancException(ErrorCode_InternalError); @@ -4766,9 +4800,8 @@ PImpl::ServerContextReference lock(*pimpl_); std::string s; - int64_t revision; // unused if (lock.GetContext().GetIndex().LookupMetadata( - s, revision, params.instanceId, + s, params.instanceId, ResourceType_Instance, MetadataType_Instance_PixelDataVR)) { hasPixelData = true; @@ -4787,7 +4820,7 @@ } } else if (lock.GetContext().GetIndex().LookupMetadata( - s, revision, params.instanceId, + s, params.instanceId, ResourceType_Instance, MetadataType_Instance_PixelDataOffset)) { // This file was stored by an older version of Orthanc, @@ -4902,7 +4935,7 @@ if (entry == NULL) { - throw OrthancException(ErrorCode_UnknownDicomTag); + throw OrthancException(ErrorCode_UnknownDicomTag, p.name); } else { @@ -5144,6 +5177,21 @@ ApplySendMultipartItem2(parameters); return true; + case _OrthancPluginService_StartStreamAnswer: + { + const _OrthancPluginStartStreamAnswer& p = + *reinterpret_cast<const _OrthancPluginStartStreamAnswer*>(parameters); + reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->StartStream(p.contentType); + return true; + } + + case _OrthancPluginService_SendStreamChunk: + { + const _OrthancPluginAnswerBuffer& p = + *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters); + reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->SendStreamItem(p.answer, p.answerSize); + return true; + } case _OrthancPluginService_ReadFile: { const _OrthancPluginReadFile& p =
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Engine/PluginsEnumerations.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsEnumerations.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Engine/PluginsEnumerations.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsEnumerations.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Engine/PluginsErrorDictionary.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsErrorDictionary.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Engine/PluginsErrorDictionary.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsErrorDictionary.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Engine/PluginsJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -147,7 +147,7 @@ } } - float PluginsJob::GetProgress() + float PluginsJob::GetProgress() const { return parameters_.getProgress(parameters_.job); } @@ -194,7 +194,7 @@ }; } - void PluginsJob::GetPublicContent(Json::Value& value) + void PluginsJob::GetPublicContent(Json::Value& value) const { if (parameters_.getContent != NULL) { @@ -232,7 +232,7 @@ } } - bool PluginsJob::Serialize(Json::Value& value) + bool PluginsJob::Serialize(Json::Value& value) const { if (parameters_.getSerialized != NULL) {
--- a/OrthancServer/Plugins/Engine/PluginsJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -58,16 +58,16 @@ virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; - virtual float GetProgress() ORTHANC_OVERRIDE; + virtual float GetProgress() const ORTHANC_OVERRIDE; - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = type_; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& value) const ORTHANC_OVERRIDE; virtual bool GetOutput(std::string& output, MimeType& mime,
--- a/OrthancServer/Plugins/Engine/PluginsManager.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsManager.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -244,8 +244,21 @@ { if (!boost::filesystem::exists(path)) { - LOG(ERROR) << "Inexistent path to plugins: " << path; - return; + boost::filesystem::path p(path); + std::string extension = p.extension().string(); + Toolbox::ToLowerCase(extension); + + if (extension == PLUGIN_EXTENSION) + { + // if this is a plugin path, fail to start + throw OrthancException(ErrorCode_SharedLibrary, "Inexistent path to plugin: " + path); + } + else + { + // it might be a directory -> just log a warning + LOG(WARNING) << "Inexistent path to plugins: " << path; + return; + } } if (boost::filesystem::is_directory(path))
--- a/OrthancServer/Plugins/Engine/PluginsManager.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsManager.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Thu Jan 30 17:41:33 2025 +0100 @@ -7,8 +7,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Thu Jan 30 17:41:33 2025 +0100 @@ -86,8 +86,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -121,7 +121,7 @@ #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER 1 #define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER 12 -#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 6 +#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 7 #if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) @@ -324,6 +324,7 @@ OrthancPluginErrorCode_AlreadyExistingTag = 2042 /*!< Cannot override the value of a tag that already exists */, OrthancPluginErrorCode_NoStorageCommitmentHandler = 2043 /*!< No request handler factory for DICOM N-ACTION SCP (storage commitment) */, OrthancPluginErrorCode_NoCGetHandler = 2044 /*!< No request handler factory for DICOM C-GET SCP */, + OrthancPluginErrorCode_DicomGetUnavailable = 2045 /*!< DicomUserConnection: The C-GET command is not supported by the remote SCP */, OrthancPluginErrorCode_UnsupportedMediaType = 3000 /*!< Unsupported media type */, _OrthancPluginErrorCode_INTERNAL = 0x7fffffff @@ -508,6 +509,8 @@ _OrthancPluginService_CompressAndAnswerImage = 2011, _OrthancPluginService_SendMultipartItem2 = 2012, _OrthancPluginService_SetHttpErrorDetails = 2013, + _OrthancPluginService_StartStreamAnswer = 2014, + _OrthancPluginService_SendStreamChunk = 2015, /* Access to the Orthanc database and API */ _OrthancPluginService_GetDicomForInstance = 3000, @@ -1444,7 +1447,7 @@ /** * @brief Callback for writing to the storage area. * - * Signature of a callback function that is triggered when Orthanc writes a file to the storage area. + * Signature of a callback function that is triggered when Orthanc writes an instance to the storage area. * * @param customData The custom data of the attachment (out) * @param uuid The UUID of the file. @@ -9727,6 +9730,67 @@ context->InvokeService(context, _OrthancPluginService_LogMessage, &m); } + + typedef struct + { + OrthancPluginRestOutput* output; + const char* contentType; + } _OrthancPluginStartStreamAnswer; + + /** + * @brief Start an HTTP stream answer. + * + * Initiates an HTTP stream answer, as the result of a REST request. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param contentType The MIME type of the items in the stream answer. + * @return 0 if success, or the error code if failure. + * @see OrthancPluginSendStreamChunk() + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStartStreamAnswer( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* contentType) + { + _OrthancPluginStartStreamAnswer params; + params.output = output; + params.contentType = contentType; + return context->InvokeService(context, _OrthancPluginService_StartStreamAnswer, ¶ms); + } + + + /** + * @brief Send a chunk as a part of an HTTP stream answer. + * + * This function sends a chunk as part of an HTTP stream + * answer that was initiated by OrthancPluginStartStreamAnswer(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param answer Pointer to the memory buffer containing the item. + * @param answerSize Number of bytes of the item. + * @return 0 if success, or the error code if failure (this notably happens + * if the connection is closed by the client). + * @see OrthancPluginStartStreamAnswer() + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendStreamChunk( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const void* answer, + uint32_t answerSize) + { + _OrthancPluginAnswerBuffer params; + params.output = output; + params.answer = answer; + params.answerSize = answerSize; + params.mimeType = NULL; + return context->InvokeService(context, _OrthancPluginService_SendStreamChunk, ¶ms); + } + + #ifdef __cplusplus } #endif
--- a/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -55,7 +55,7 @@ int32 compression_type = 5; // opaque "CompressionType" in Orthanc uint64 compressed_size = 6; string compressed_hash = 7; - string custom_data = 8; // added in v 1.12.5 + string custom_data = 8; // added in v 1.12.7 } enum ResourceType { @@ -89,6 +89,12 @@ ORDERING_DIRECTION_DESC = 1; } +enum OrderingCast { + ORDERING_CAST_STRING = 0; + ORDERING_CAST_INT = 1; + ORDERING_CAST_FLOAT = 2; +} + message ServerIndexChange { int64 seq = 1; int32 change_type = 2; // opaque "ChangeType" in Orthanc @@ -315,6 +321,7 @@ OPERATION_UPDATE_AND_GET_STATISTICS = 49; // New in Orthanc 1.12.3 OPERATION_FIND = 50; // New in Orthanc 1.12.5 OPERATION_GET_CHANGES_EXTENDED = 51; // New in Orthanc 1.12.5 + OPERATION_COUNT_RESOURCES = 52; // New in Orthanc 1.12.5 } message Rollback { @@ -877,15 +884,17 @@ bool retrieve_identifiers = 1; repeated int32 retrieve_metadata = 2; repeated Tag retrieve_main_dicom_tags = 3; + bool retrieve_count = 4; } message Ordering { OrderingKeyType key_type = 1; OrderingDirection direction = 2; - uint32 tag_group = 3; - uint32 tag_element = 4; - bool is_identifier_tag = 5; - ResourceType tag_level = 6; - int32 metadata = 7; + OrderingCast cast = 3; + uint32 tag_group = 4; + uint32 tag_element = 5; + bool is_identifier_tag = 6; + ResourceType tag_level = 7; + int32 metadata = 8; } // Part 1 of the request: Constraints @@ -926,15 +935,7 @@ message Metadata { int32 key = 1; string value = 2; - } - message MultipleTags { - uint32 group = 1; - uint32 element = 2; - repeated string values = 3; - } - message MultipleMetadata { - int32 key = 1; - repeated string values = 2; + int64 revision = 3; } message ResourceContent { repeated Tag main_dicom_tags = 1; @@ -942,8 +943,9 @@ } message ChildrenContent { repeated string identifiers = 1; - repeated MultipleTags main_dicom_tags = 2; - repeated MultipleMetadata metadata = 3; + repeated Tag main_dicom_tags = 2; + repeated Metadata metadata = 3; // As of Orthanc 1.12.5, the "revision" field is unused in this case + uint64 count = 4; } int64 internal_id = 1; @@ -961,6 +963,15 @@ string one_instance_public_id = 13; repeated Metadata one_instance_metadata = 14; repeated FileInfo one_instance_attachments = 15; + repeated int64 attachments_revisions = 16; + } +} + +message CountResources +{ + message Response + { + uint64 count = 1; } } @@ -1020,6 +1031,7 @@ UpdateAndGetStatistics.Request update_and_get_statistics = 149; Find.Request find = 150; GetChangesExtended.Request get_changes_extended = 151; + Find.Request count_resources = 152; } message TransactionResponse { @@ -1073,8 +1085,9 @@ ListLabels.Response list_labels = 147; IncrementGlobalProperty.Response increment_global_property = 148; UpdateAndGetStatistics.Response update_and_get_statistics = 149; - repeated Find.Response find = 150; // One message per found resources + repeated Find.Response find = 150; // One message per found resource GetChangesExtended.Response get_changes_extended = 151; + CountResources.Response count_resources = 152; } enum RequestType {
--- a/OrthancServer/Plugins/Samples/AutomatedJpeg2kCompression/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/AutomatedJpeg2kCompression/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/AutomatedJpeg2kCompression/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/AutomatedJpeg2kCompression/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Basic/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Basic/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Basic/Plugin.c Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Basic/Plugin.c Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -334,9 +334,9 @@ std::vector<const char*> headersValues_; public: - explicit PluginHttpHeaders(const std::map<std::string, std::string>& httpHeaders) - { - for (std::map<std::string, std::string>::const_iterator + explicit PluginHttpHeaders(const HttpHeaders& httpHeaders) + { + for (HttpHeaders::const_iterator it = httpHeaders.begin(); it != httpHeaders.end(); ++it) { headersKeys_.push_back(it->first.c_str()); @@ -361,7 +361,7 @@ }; bool MemoryBuffer::RestApiGet(const std::string& uri, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins) { Clear(); @@ -400,7 +400,7 @@ bool MemoryBuffer::RestApiPost(const std::string& uri, const void* body, size_t bodySize, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins) { MemoryBuffer answerHeaders; @@ -422,7 +422,7 @@ bool MemoryBuffer::RestApiPost(const std::string& uri, const Json::Value& body, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins) { std::string s; @@ -1490,7 +1490,7 @@ bool RestApiGetString(std::string& result, const std::string& uri, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins) { MemoryBuffer answer; @@ -1508,7 +1508,7 @@ bool RestApiGet(Json::Value& result, const std::string& uri, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins) { MemoryBuffer answer; @@ -1598,7 +1598,7 @@ bool RestApiPost(Json::Value& result, const std::string& uri, const Json::Value& body, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins) { MemoryBuffer answer; @@ -1963,7 +1963,7 @@ bool OrthancPeers::DoGet(MemoryBuffer& target, size_t index, const std::string& uri, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { if (index >= index_.size()) { @@ -1994,7 +1994,7 @@ bool OrthancPeers::DoGet(MemoryBuffer& target, const std::string& name, const std::string& uri, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { size_t index; return (LookupName(index, name) && @@ -2005,7 +2005,7 @@ bool OrthancPeers::DoGet(Json::Value& target, size_t index, const std::string& uri, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { MemoryBuffer buffer; @@ -2024,7 +2024,7 @@ bool OrthancPeers::DoGet(Json::Value& target, const std::string& name, const std::string& uri, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { MemoryBuffer buffer; @@ -2044,7 +2044,7 @@ const std::string& name, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { size_t index; return (LookupName(index, name) && @@ -2056,7 +2056,7 @@ size_t index, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { MemoryBuffer buffer; @@ -2076,7 +2076,7 @@ const std::string& name, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { MemoryBuffer buffer; @@ -2096,7 +2096,7 @@ size_t index, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { if (index >= index_.size()) { @@ -2133,7 +2133,7 @@ bool OrthancPeers::DoPut(size_t index, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { if (index >= index_.size()) { @@ -2169,7 +2169,7 @@ bool OrthancPeers::DoPut(const std::string& name, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { size_t index; return (LookupName(index, name) && @@ -2179,7 +2179,7 @@ bool OrthancPeers::DoDelete(size_t index, const std::string& uri, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { if (index >= index_.size()) { @@ -2208,7 +2208,7 @@ bool OrthancPeers::DoDelete(const std::string& name, const std::string& uri, - const std::map<std::string, std::string>& headers) const + const HttpHeaders& headers) const { size_t index; return (LookupName(index, name) && @@ -2923,12 +2923,12 @@ std::vector<const char*> headersValues_; public: - HeadersWrapper(const HttpClient::HttpHeaders& headers) + HeadersWrapper(const HttpHeaders& headers) { headersKeys_.reserve(headers.size()); headersValues_.reserve(headers.size()); - for (HttpClient::HttpHeaders::const_iterator it = headers.begin(); it != headers.end(); ++it) + for (HttpHeaders::const_iterator it = headers.begin(); it != headers.end(); ++it) { headersKeys_.push_back(it->first.c_str()); headersValues_.push_back(it->second.c_str()); @@ -3076,11 +3076,11 @@ class MemoryAnswer : public HttpClient::IAnswer { private: - HttpClient::HttpHeaders headers_; - ChunkedBuffer body_; + HttpHeaders headers_; + ChunkedBuffer body_; public: - const HttpClient::HttpHeaders& GetHeaders() const + const HttpHeaders& GetHeaders() const { return headers_; } @@ -3168,6 +3168,35 @@ #endif + static void DecodeHttpHeaders(HttpHeaders& target, + const MemoryBuffer& source) + { + Json::Value v; + source.ToJson(v); + + if (v.type() != Json::objectValue) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + Json::Value::Members members = v.getMemberNames(); + target.clear(); + + for (size_t i = 0; i < members.size(); i++) + { + const Json::Value& h = v[members[i]]; + if (h.type() != Json::stringValue) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + else + { + target[members[i]] = h.asString(); + } + } + } + + void HttpClient::ExecuteWithoutStream(uint16_t& httpStatus, HttpHeaders& answerHeaders, std::string& answerBody, @@ -3208,30 +3237,7 @@ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); } - Json::Value v; - answerHeadersBuffer.ToJson(v); - - if (v.type() != Json::objectValue) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - - Json::Value::Members members = v.getMemberNames(); - answerHeaders.clear(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& h = v[members[i]]; - if (h.type() != Json::stringValue) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - else - { - answerHeaders[members[i]] = h.asString(); - } - } - + DecodeHttpHeaders(answerHeaders, answerHeadersBuffer); answerBodyBuffer.ToString(answerBody); } @@ -4061,7 +4067,7 @@ } #endif - void GetHttpHeaders(std::map<std::string, std::string>& result, const OrthancPluginHttpRequest* request) + void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request) { result.clear(); @@ -4114,4 +4120,135 @@ SetPluginProperty(pluginIdentifier, _OrthancPluginProperty_OrthancExplorer, javascript); #endif } + + +#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 + RestApiClient::RestApiClient() : + method_(OrthancPluginHttpMethod_Get), + path_("/"), + afterPlugins_(false), + httpStatus_(0) + { + } +#endif + + +#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 + void RestApiClient::AddRequestHeader(const std::string& key, + const std::string& value) + { + if (requestHeaders_.find(key) == requestHeaders_.end()) + { + requestHeaders_[key] = value; + } + else + { + ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); + } + } +#endif + + +#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 + bool RestApiClient::Execute() + { + if (requestBody_.size() > 0xffffffffu) + { + ORTHANC_PLUGINS_LOG_ERROR("Cannot handle body size > 4GB"); + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + PluginHttpHeaders converted(requestHeaders_); + + MemoryBuffer body; + MemoryBuffer headers; + + OrthancPluginErrorCode code = OrthancPluginCallRestApi(GetGlobalContext(), *body, *headers, &httpStatus_, method_, path_.c_str(), + requestHeaders_.size(), converted.GetKeys(), converted.GetValues(), + requestBody_.c_str(), requestBody_.size(), afterPlugins_ ? 1 : 0); + + answerHeaders_.clear(); + answerBody_.clear(); + + if (code == OrthancPluginErrorCode_Success) + { + if (httpStatus_ == 0) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + DecodeHttpHeaders(answerHeaders_, headers); + body.ToString(answerBody_); + return true; + } + else + { + if (code == OrthancPluginErrorCode_UnknownResource || + code == OrthancPluginErrorCode_InexistentItem) + { + httpStatus_ = 404; + return false; + } + else + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); + } + } + } +#endif + + +#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 + uint16_t RestApiClient::GetHttpStatus() const + { + if (httpStatus_ == 0) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); + } + else + { + return httpStatus_; + } + } +#endif + + +#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 + bool RestApiClient::LookupAnswerHeader(std::string& value, + const std::string& key) const + { + if (httpStatus_ == 0) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); + } + else + { + HttpHeaders::const_iterator found = answerHeaders_.find(key); + if (found == answerHeaders_.end()) + { + return false; + } + else + { + value = found->second; + return true; + } + } + } +#endif + + +#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 + const std::string& RestApiClient::GetAnswerBody() const + { + if (httpStatus_ == 0) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); + } + else + { + return answerBody_; + } + } +#endif }
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -170,6 +170,8 @@ namespace OrthancPlugins { + typedef std::map<std::string, std::string> HttpHeaders; + typedef void (*RestCallback) (OrthancPluginRestOutput* output, const char* url, const OrthancPluginHttpRequest* request); @@ -257,7 +259,7 @@ bool applyPlugins); bool RestApiGet(const std::string& uri, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins); bool RestApiPost(const std::string& uri, @@ -277,13 +279,13 @@ #if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 bool RestApiPost(const std::string& uri, const Json::Value& body, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins); bool RestApiPost(const std::string& uri, const void* body, size_t bodySize, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins); #endif @@ -581,7 +583,7 @@ bool RestApiGet(Json::Value& result, const std::string& uri, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins); bool RestApiGetString(std::string& result, @@ -590,7 +592,7 @@ bool RestApiGetString(std::string& result, const std::string& uri, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins); bool RestApiPost(std::string& result, @@ -609,7 +611,7 @@ bool RestApiPost(Json::Value& result, const std::string& uri, const Json::Value& body, - const std::map<std::string, std::string>& httpHeaders, + const HttpHeaders& httpHeaders, bool applyPlugins); #endif @@ -829,64 +831,64 @@ bool DoGet(MemoryBuffer& target, size_t index, const std::string& uri, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoGet(MemoryBuffer& target, const std::string& name, const std::string& uri, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoGet(Json::Value& target, size_t index, const std::string& uri, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoGet(Json::Value& target, const std::string& name, const std::string& uri, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoPost(MemoryBuffer& target, size_t index, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoPost(MemoryBuffer& target, const std::string& name, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoPost(Json::Value& target, size_t index, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoPost(Json::Value& target, const std::string& name, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoPut(size_t index, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoPut(const std::string& name, const std::string& uri, const std::string& body, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoDelete(size_t index, const std::string& uri, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; bool DoDelete(const std::string& name, const std::string& uri, - const std::map<std::string, std::string>& headers) const; + const HttpHeaders& headers) const; }; #endif @@ -996,8 +998,6 @@ class HttpClient : public boost::noncopyable { public: - typedef std::map<std::string, std::string> HttpHeaders; - class IRequestBody : public boost::noncopyable { public: @@ -1397,7 +1397,7 @@ }; // helper method to convert Http headers from the plugin SDK to a std::map -void GetHttpHeaders(std::map<std::string, std::string>& result, const OrthancPluginHttpRequest* request); +void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request); #if HAS_ORTHANC_PLUGIN_WEBDAV == 1 class IWebDavCollection : public boost::noncopyable @@ -1508,4 +1508,88 @@ void ExtendOrthancExplorer(const std::string& pluginIdentifier, const std::string& javascript); + + +#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1 + class RestApiClient : public boost::noncopyable + { + private: + // Request + OrthancPluginHttpMethod method_; + std::string path_; + HttpHeaders requestHeaders_; + std::string requestBody_; + bool afterPlugins_; + + // Answer + uint16_t httpStatus_; + HttpHeaders answerHeaders_; + std::string answerBody_; + + public: + RestApiClient(); + + void SetMethod(OrthancPluginHttpMethod method) + { + method_ = method; + } + + OrthancPluginHttpMethod GetMethod() const + { + return method_; + } + + void SetPath(const std::string& path) + { + path_ = path; + } + + const std::string& GetPath() const + { + return path_; + } + + void AddRequestHeader(const std::string& key, + const std::string& value); + + const HttpHeaders& GetRequestHeaders() const + { + return requestHeaders_; + } + + void SetRequestBody(const std::string& body) + { + requestBody_ = body; + } + + void SwapRequestBody(std::string& body) + { + requestBody_.swap(body); + } + + void SetAfterPlugins(bool afterPlugins) + { + afterPlugins_ = afterPlugins; + } + + bool IsAfterPlugins() const + { + return afterPlugins_; + } + + const std::string& GetRequestBody() const + { + return requestBody_; + } + + bool Execute(); + + uint16_t GetHttpStatus() const; + + bool LookupAnswerHeader(std::string& value, + const std::string& key) const; + + const std::string& GetAnswerBody() const; + }; +#endif }
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginException.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginException.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Common/OrthancPlugins.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Common/OrthancPlugins.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginsExports.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginsExports.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ConnectivityChecks/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ConnectivityChecks/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ConnectivityChecks/JavaScriptLibraries.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ConnectivityChecks/JavaScriptLibraries.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ConnectivityChecks/OrthancFrameworkDependencies.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ConnectivityChecks/OrthancFrameworkDependencies.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ConnectivityChecks/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ConnectivityChecks/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ConnectivityChecks/WebResources/app.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ConnectivityChecks/WebResources/app.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/CustomImageDecoder/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/CustomImageDecoder/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/CustomImageDecoder/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/CustomImageDecoder/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/DelayedDeletion/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/LargeDeleteJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/DelayedDeletion/LargeDeleteJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/LargeDeleteJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/DelayedDeletion/LargeDeleteJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/OrthancFrameworkDependencies.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/DelayedDeletion/OrthancFrameworkDependencies.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/PendingDeletionsDatabase.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/DelayedDeletion/PendingDeletionsDatabase.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/PendingDeletionsDatabase.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/DelayedDeletion/PendingDeletionsDatabase.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/DelayedDeletion/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Housekeeper/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Housekeeper/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -566,7 +566,7 @@ { Json::Value result; - if (needsReconstruct || needsReingest) + if (needsReconstruct || needsReingest ||force_) { Json::Value request; if (needsReingest) @@ -859,12 +859,15 @@ "StorageCompressionChange": true, "MainDicomTagsChange": true, "UnnecessaryDicomAsJsonFiles": true, + "IngestTranscodingChange": true, "DicomWebCacheChange": true // new in 1.12.2 }, - // When rebuilding MainDicomTags, limit to a single level of resource. - // Allowed values: "Patient", "Study", "Series", "Instance" - "LimitMainDicomTagsReconstructLevel": "Study" + // When rebuilding MainDicomTags, limit to a single level of resource + // which can greatly improve performances e.g. if you have only updated + // the Study level ExtraMainDicomTags. + // Allowed values: "Patient", "Study", "Series", "Instance", "All" + "LimitMainDicomTagsReconstructLevel": "All" } } @@ -887,11 +890,12 @@ triggerOnDicomWebCacheChange_ = triggers.GetBooleanValue("DicomWebCacheChange", true); } - limitMainDicomTagsReconstructLevel_ = housekeeper.GetStringValue("LimitMainDicomTagsReconstructLevel", ""); + limitMainDicomTagsReconstructLevel_ = housekeeper.GetStringValue("LimitMainDicomTagsReconstructLevel", "All"); if (limitMainDicomTagsReconstructLevel_ != "Patient" && limitMainDicomTagsReconstructLevel_ != "Study" - && limitMainDicomTagsReconstructLevel_ != "Series" && limitMainDicomTagsReconstructLevel_ != "Instance") + && limitMainDicomTagsReconstructLevel_ != "Series" && limitMainDicomTagsReconstructLevel_ != "Instance" && limitMainDicomTagsReconstructLevel_ != "All") { ORTHANC_PLUGINS_LOG_ERROR("Housekeeper invalid value for 'LimitMainDicomTagsReconstructLevel': '" + limitMainDicomTagsReconstructLevel_ + "'"); + return -1; } else if (limitMainDicomTagsReconstructLevel_ == "Patient") {
--- a/OrthancServer/Plugins/Samples/ModalityWorklists/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ModalityWorklists/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ModalityWorklists/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ModalityWorklists/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -29,10 +29,11 @@ #include "../../../../OrthancFramework/Sources/OrthancException.h" #include "../Common/OrthancPluginCppWrapper.h" - +#include <dcmtk/dcmdata/dcuid.h> /* for variable dcmAllStorageSOPClassUIDs */ DicomFilter::DicomFilter() : - hasAcceptedTransferSyntaxes_(false) + hasAcceptedTransferSyntaxes_(false), + hasAcceptedStorageClasses_(false) { { OrthancPlugins::OrthancConfiguration config; @@ -200,6 +201,18 @@ } +void DicomFilter::GetProposedStorageTransferSyntaxes(std::list<Orthanc::DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) +{ + // default TS + target.push_back(Orthanc::DicomTransferSyntax_LittleEndianExplicit); + target.push_back(Orthanc::DicomTransferSyntax_LittleEndianImplicit); + target.push_back(Orthanc::DicomTransferSyntax_BigEndianExplicit); +} + + bool DicomFilter::IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) @@ -207,3 +220,46 @@ boost::shared_lock<boost::shared_mutex> lock(mutex_); return unknownSopClassAccepted_; } + + +void DicomFilter::GetAcceptedSopClasses(std::set<std::string>& sopClasses, size_t maxCount) +{ + boost::unique_lock<boost::shared_mutex> lock(mutex_); + + if (!hasAcceptedStorageClasses_) + { + Json::Value jsonSopClasses; + + if (!OrthancPlugins::RestApiGet(jsonSopClasses, "/tools/accepted-sop-classes", false) || + jsonSopClasses.type() != Json::arrayValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + for (Json::Value::ArrayIndex i = 0; i < jsonSopClasses.size(); i++) + { + if (jsonSopClasses[i].type() != Json::stringValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + acceptedStorageClasses_.insert(jsonSopClasses[i].asString()); + } + } + } + + hasAcceptedStorageClasses_ = true; + } + + std::set<std::string>::const_iterator it = acceptedStorageClasses_.begin(); + size_t count = 0; + + while (it != acceptedStorageClasses_.end() && (maxCount == 0 || count < maxCount)) + { + sopClasses.insert(*it); + count++; + ++it; + } +}
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/DicomFilter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -44,6 +44,8 @@ bool hasAcceptedTransferSyntaxes_; std::set<Orthanc::DicomTransferSyntax> acceptedTransferSyntaxes_; + bool hasAcceptedStorageClasses_; + std::set<std::string> acceptedStorageClasses_; public: DicomFilter(); @@ -62,7 +64,15 @@ const std::string& remoteAet, const std::string& calledAet) ORTHANC_OVERRIDE; + virtual void GetProposedStorageTransferSyntaxes(std::list<Orthanc::DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) ORTHANC_OVERRIDE; + + virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet, const std::string& calledAet) ORTHANC_OVERRIDE; + + virtual void GetAcceptedSopClasses(std::set<std::string>& sopClasses, size_t maxCount) ORTHANC_OVERRIDE; };
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/FindRequestHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/FindRequestHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/FindRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/FindRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/MoveRequestHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/MoveRequestHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/MoveRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/MoveRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/MultitenantDicomServer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/MultitenantDicomServer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/MultitenantDicomServer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/MultitenantDicomServer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/OrthancFrameworkDependencies.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/OrthancFrameworkDependencies.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/PluginEnumerations.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/PluginEnumerations.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/PluginToolbox.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/PluginToolbox.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/PluginToolbox.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/PluginToolbox.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/StoreRequestHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/StoreRequestHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/MultitenantDicom/StoreRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/MultitenantDicom/StoreRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Sanitizer/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Sanitizer/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ServeFolders/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ServeFolders/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/ServeFolders/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/ServeFolders/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/StorageArea/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/StorageArea/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/StorageArea/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/StorageArea/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/StorageCommitmentScp/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/StorageCommitmentScp/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/StorageCommitmentScp/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/StorageCommitmentScp/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/WebDavFilesystem/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/WebDavFilesystem/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/WebDavFilesystem/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/WebDavFilesystem/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/WebSkeleton/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/WebSkeleton/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/WebSkeleton/Configuration.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/WebSkeleton/Configuration.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/WebSkeleton/Framework/EmbedResources.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/WebSkeleton/Framework/EmbedResources.py Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/WebSkeleton/Framework/Framework.cmake Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/WebSkeleton/Framework/Framework.cmake Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Plugins/Samples/WebSkeleton/Framework/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Plugins/Samples/WebSkeleton/Framework/Plugin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Configuration.json Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Configuration.json Thu Jan 30 17:41:33 2025 +0100 @@ -15,15 +15,11 @@ // Path to the directory that holds the heavyweight files (i.e. the // raw DICOM instances). Backslashes must be either escaped by // doubling them, or replaced by forward slashes "/". - // If a relative path is provided, it is relative to the configuration - // file path. It is advised to provide an absolute path. "StorageDirectory" : "OrthancStorage", // Path to the directory that holds the SQLite index (if unset, the // value of StorageDirectory is used). This index could be stored on // a RAM-drive or a SSD device for performance reasons. - // If a relative path is provided, it is relative to the configuration - // file path. It is advised to provide an absolute path. "IndexDirectory" : "OrthancStorage", // Path to the directory where Orthanc stores its large temporary @@ -206,6 +202,43 @@ // SOP classes (aka. "promiscuous mode") "UnknownSopClassAccepted" : false, + // The list of accepted Storage SOP classes. + // If empty or not defined, this list defaults + // to all storage classes defined in DCMTK in case of + // C-STORE SCP and to a reduced list of 120 common storage + // classes in case of C-GET SCU. + // List of DCMTK default Storage SOP Classes: + // https://github.com/DCMTK/dcmtk/blob/410ffe2019b9db6a8f4036daac742a6f5e4d36c2/dcmdata/libsrc/dcuid.cc#L664 + // Each entry can contain wildcards ("?" or "*") to add + // subsets of SOP classes that are defined in DCMTK defaults. + // "?" accepts any single character at that position. + // "*" accepts any string value at that position. + // If you want to add a a SOP class that is not defined in + // DCMTK defaults, you must add it explicitely. + // (new in Orthanc 1.12.6) + // Example to add a non standard class + // and keep the default ones: + // "AcceptedSopClasses" : [ + // "1.3.12.2.1107.5.9.1", + // "1.2.840.*" + // ] + // Example to limit to 2 SOP Classes: + // "AcceptedSopClasses" : [ + // "1.2.840.10008.5.1.4.1.1.2", + // "1.2.840.10008.5.1.4.1.1.4" + // ] + + // The list of rejected Storage SOP classes. + // This configuration is only meaningful if + // "AcceptedSopClasses" is using regular expressions + // or if it is not defined. + // Each entry can contain wildcards ("?" or "*"). + // (new in Orthanc 1.12.6) + // "RejectedSopClasses" : [ + // "1.2.840.10008.5.1.4.1.1.2", + // "1.2.840.10008.5.1.4.1.1.4" + // ] + // Set the timeout (in seconds) after which the DICOM associations // are closed by the Orthanc SCP (server) if no further DIMSE // command is received from the SCU (client). @@ -463,6 +496,10 @@ * for Orthanc when initiating an SCU to this very specific * modality. Similarly, "Timeout" allows one to overwrite the * global value "DicomScuTimeout" on a per-modality basis. + * + * The "RetrieveMethod" option allows one to overwrite the global + * "DicomDefaultRetrieveMethod" configuration option for this + * specific modality. (Allowed values: "C-MOVE" or "C-GET"). **/ //"untrusted" : { // "AET" : "ORTHANC", @@ -479,7 +516,8 @@ // "AllowTranscoding" : true, // new in 1.7.0 // "UseDicomTls" : false, // new in 1.9.0 // "LocalAet" : "HELLO", // new in 1.9.0 - // "Timeout" : 60 // new in 1.9.1 + // "Timeout" : 60, // new in 1.9.1 + // "RetrieveMethod": "C-MOVE" // new in 1.12.6 //} }, @@ -493,6 +531,13 @@ // accept C-FIND requests from Orthanc (new in Orthanc 1.8.1). "DicomEchoChecksFind" : false, + // Wheter Orthanc uses C-MOVE or C-GET to retrieve a resource after + // a C-Find (when calling /queries/.../retrieve). + // This configuration can be overriden for each modality by providing + // "RetrieveMethod" in the "DicomModalities" entry. + // (new in Orthanc 1.12.6) + "DicomDefaultRetrieveMethod" : "C-MOVE", + // The timeout (in seconds) after which the DICOM associations are // considered as closed by the Orthanc SCU (client) if the remote // DICOM SCP (server) does not answer. @@ -576,10 +621,10 @@ // Set the timeout for HTTP requests issued by Orthanc (in seconds). "HttpTimeout" : 60, - // Enable the verification of the peers during HTTPS requests. This - // option must be set to "false" if using self-signed certificates. - // Pay attention that setting this option to "false" results in - // security risks! + // Enable the verification of the peers certificates during HTTPS + // requests. Setting this option to false is equivalent to the + // "--insecure" curl option. Pay attention that setting this option + // to "false" results in security risks! // Reference: http://curl.haxx.se/docs/sslcerts.html "HttpsVerifyPeers" : true, @@ -589,7 +634,11 @@ // verify the peers. The file may contain multiple CA // certificates. The certificate(s) must be in PEM format." On // Debian-based systems, this option can be set to - // "/etc/ssl/certs/ca-certificates.crt" + // "/etc/ssl/certs/ca-certificates.crt". + // Starting with Orthanc 1.12.6 and provided that Orthanc has been + // built with libcurl > 8.2.0, when this option is empty, + // Orthanc uses the operating system native CA store ("--ca-native" + // option) "HttpsCACertificates" : "", @@ -1008,14 +1057,29 @@ // from a lower resource level; e.g. when requesting "StudyDescription" at // Patient level. // (new in Orthanc 1.12.5) - "W005_RequestingTagFromLowerResourceLevel": true + "W005_RequestingTagFromLowerResourceLevel": true, + + // Display a warning when a user performs a find request and requests a tag + // from the DICOM Meta Header. + // (new in Orthanc 1.12.5) + "W006_RequestingTagFromMetaHeader": true, + + // Display a warning when a user requests a tag that can not be read from disk + // because "StorageAccessOnFind" is set to "Never". + // (new in Orthanc 1.12.5) + "W007_MissingRequestedTagsNotReadFromDisk": true }, // Configure Orthanc in read only mode. // In this mode, many Orthanc features that requires a write access to the // Index DB or the disk storage won't be available at all. // (new in Orthanc 1.12.5) - "ReadOnly" : false + "ReadOnly" : false, + // Maximum number of DCMTK transcoders that are simultaneously running + // at any given time. A value of "0" indicates to use all the + // available CPU logical cores. Prior to Orthanc 1.12.6, there were not limit. + // (new in Orthanc 1.12.6) + "MaximumConcurrentDcmtkTranscoders" : 0 }
--- a/OrthancServer/Resources/DicomConformanceStatement.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/DicomConformanceStatement.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/DicomConformanceStatement.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/DicomConformanceStatement.txt Thu Jan 30 17:41:33 2025 +0100 @@ -209,6 +209,16 @@ MOVEStudyRootQueryRetrieveInformationModel | 1.2.840.10008.5.1.4.1.2.2.2 +------------------- +Get SCU Conformance +------------------- + +Orthanc supports the following SOP Classes as an SCU for C-Get: + + GETPatientRootQueryRetrieveInformationModel | 1.2.840.10008.5.1.4.1.2.1.3 + GETStudyRootQueryRetrieveInformationModel | 1.2.840.10008.5.1.4.1.2.2.3 + + ----------------- Transfer Syntaxes -----------------
--- a/OrthancServer/Resources/Fonts/GenerateFont.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Fonts/GenerateFont.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/GenerateAnonymizationProfile.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/GenerateAnonymizationProfile.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupIdentifierQuery.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,205 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "LookupIdentifierQuery.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/OrthancException.h" -#include "../ServerToolbox.h" -#include "SetOfResources.h" - -#include <cassert> - - - -namespace Orthanc -{ - LookupIdentifierQuery::SingleConstraint:: - SingleConstraint(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value) : - tag_(tag), - type_(type), - value_(ServerToolbox::NormalizeIdentifier(value)) - { - } - - - LookupIdentifierQuery::RangeConstraint:: - RangeConstraint(const DicomTag& tag, - const std::string& start, - const std::string& end) : - tag_(tag), - start_(ServerToolbox::NormalizeIdentifier(start)), - end_(ServerToolbox::NormalizeIdentifier(end)) - { - } - - - LookupIdentifierQuery::Disjunction::~Disjunction() - { - for (size_t i = 0; i < singleConstraints_.size(); i++) - { - delete singleConstraints_[i]; - } - - for (size_t i = 0; i < rangeConstraints_.size(); i++) - { - delete rangeConstraints_[i]; - } - } - - - void LookupIdentifierQuery::Disjunction::Add(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value) - { - singleConstraints_.push_back(new SingleConstraint(tag, type, value)); - } - - - void LookupIdentifierQuery::Disjunction::AddRange(const DicomTag& tag, - const std::string& start, - const std::string& end) - { - rangeConstraints_.push_back(new RangeConstraint(tag, start, end)); - } - - - LookupIdentifierQuery::~LookupIdentifierQuery() - { - for (Disjunctions::iterator it = disjunctions_.begin(); - it != disjunctions_.end(); ++it) - { - delete *it; - } - } - - - bool LookupIdentifierQuery::IsIdentifier(const DicomTag& tag) - { - return ServerToolbox::IsIdentifier(tag, level_); - } - - - void LookupIdentifierQuery::AddConstraint(DicomTag tag, - IdentifierConstraintType type, - const std::string& value) - { - assert(IsIdentifier(tag)); - disjunctions_.push_back(new Disjunction); - disjunctions_.back()->Add(tag, type, value); - } - - - void LookupIdentifierQuery::AddRange(DicomTag tag, - const std::string& start, - const std::string& end) - { - assert(IsIdentifier(tag)); - disjunctions_.push_back(new Disjunction); - disjunctions_.back()->AddRange(tag, start, end); - } - - - LookupIdentifierQuery::Disjunction& LookupIdentifierQuery::AddDisjunction() - { - disjunctions_.push_back(new Disjunction); - return *disjunctions_.back(); - } - - - void LookupIdentifierQuery::Apply(std::list<std::string>& result, - IDatabaseWrapper& database) - { - SetOfResources resources(database, level_); - Apply(resources, database); - - resources.Flatten(result); - } - - - void LookupIdentifierQuery::Apply(SetOfResources& result, - IDatabaseWrapper& database) - { - for (size_t i = 0; i < disjunctions_.size(); i++) - { - std::list<int64_t> a; - - for (size_t j = 0; j < disjunctions_[i]->GetSingleConstraintsCount(); j++) - { - const SingleConstraint& constraint = disjunctions_[i]->GetSingleConstraint(j); - std::list<int64_t> b; - database.LookupIdentifier(b, level_, constraint.GetTag(), - constraint.GetType(), constraint.GetValue()); - - a.splice(a.end(), b); - } - - for (size_t j = 0; j < disjunctions_[i]->GetRangeConstraintsCount(); j++) - { - const RangeConstraint& constraint = disjunctions_[i]->GetRangeConstraint(j); - std::list<int64_t> b; - database.LookupIdentifierRange(b, level_, constraint.GetTag(), - constraint.GetStart(), constraint.GetEnd()); - - a.splice(a.end(), b); - } - - result.Intersect(a); - } - } - - - void LookupIdentifierQuery::Print(std::ostream& s) const - { - s << "Constraint: " << std::endl; - for (Disjunctions::const_iterator - it = disjunctions_.begin(); it != disjunctions_.end(); ++it) - { - if (it == disjunctions_.begin()) - s << " "; - else - s << "OR "; - - for (size_t j = 0; j < (*it)->GetSingleConstraintsCount(); j++) - { - const SingleConstraint& c = (*it)->GetSingleConstraint(j); - s << FromDcmtkBridge::GetTagName(c.GetTag(), ""); - - switch (c.GetType()) - { - case IdentifierConstraintType_Equal: s << " == "; break; - case IdentifierConstraintType_SmallerOrEqual: s << " <= "; break; - case IdentifierConstraintType_GreaterOrEqual: s << " >= "; break; - case IdentifierConstraintType_Wildcard: s << " ~= "; break; - default: - s << " ? "; - } - - s << c.GetValue() << std::endl; - } - } - } -}
--- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupIdentifierQuery.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../IDatabaseWrapper.h" - -#include "SetOfResources.h" - -#include <vector> -#include <boost/noncopyable.hpp> - -namespace Orthanc -{ - /** - * Primitive for wildcard matching, as defined in DICOM: - * http://dicom.nema.org/dicom/2013/output/chtml/part04/sect_C.2.html#sect_C.2.2.2.4 - * - * "Any occurrence of an "*" or a "?", then "*" shall match any - * sequence of characters (including a zero length value) and "?" - * shall match any single character. This matching is case - * sensitive, except for Attributes with an PN Value - * Representation (e.g., Patient Name (0010,0010))." - * - * Pay attention to the fact that "*" (resp. "?") generally - * corresponds to "%" (resp. "_") in primitive LIKE of SQL. The - * values "%", "_", "\" should in the user request should - * respectively be escaped as "\%", "\_" and "\\". - * - * This matching must be case sensitive: The special case of PN VR - * is taken into consideration by normalizing the query string in - * method "NormalizeIdentifier()". - **/ - - class LookupIdentifierQuery : public boost::noncopyable - { - // This class encodes a conjunction ("AND") of disjunctions. Each - // disjunction represents an "OR" of several constraints. - - public: - class SingleConstraint - { - private: - DicomTag tag_; - IdentifierConstraintType type_; - std::string value_; - - public: - SingleConstraint(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value); - - const DicomTag& GetTag() const - { - return tag_; - } - - IdentifierConstraintType GetType() const - { - return type_; - } - - const std::string& GetValue() const - { - return value_; - } - }; - - - class RangeConstraint - { - private: - DicomTag tag_; - std::string start_; - std::string end_; - - public: - RangeConstraint(const DicomTag& tag, - const std::string& start, - const std::string& end); - - const DicomTag& GetTag() const - { - return tag_; - } - - const std::string& GetStart() const - { - return start_; - } - - const std::string& GetEnd() const - { - return end_; - } - }; - - - class Disjunction : public boost::noncopyable - { - private: - std::vector<SingleConstraint*> singleConstraints_; - std::vector<RangeConstraint*> rangeConstraints_; - - public: - ~Disjunction(); - - void Add(const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value); - - void AddRange(const DicomTag& tag, - const std::string& start, - const std::string& end); - - size_t GetSingleConstraintsCount() const - { - return singleConstraints_.size(); - } - - const SingleConstraint& GetSingleConstraint(size_t i) const - { - return *singleConstraints_[i]; - } - - size_t GetRangeConstraintsCount() const - { - return rangeConstraints_.size(); - } - - const RangeConstraint& GetRangeConstraint(size_t i) const - { - return *rangeConstraints_[i]; - } - }; - - - private: - typedef std::vector<Disjunction*> Disjunctions; - - ResourceType level_; - Disjunctions disjunctions_; - - public: - LookupIdentifierQuery(ResourceType level) : level_(level) - { - } - - ~LookupIdentifierQuery(); - - bool IsIdentifier(const DicomTag& tag); - - void AddConstraint(DicomTag tag, - IdentifierConstraintType type, - const std::string& value); - - void AddRange(DicomTag tag, - const std::string& start, - const std::string& end); - - Disjunction& AddDisjunction(); - - ResourceType GetLevel() const - { - return level_; - } - - // The database must be locked - void Apply(std::list<std::string>& result, - IDatabaseWrapper& database); - - void Apply(SetOfResources& result, - IDatabaseWrapper& database); - - void Print(std::ostream& s) const; - }; -}
--- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupResource.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,469 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "LookupResource.h" - -#include "../../Core/OrthancException.h" -#include "../../Core/FileStorage/StorageAccessor.h" -#include "../ServerToolbox.h" -#include "../../Core/DicomParsing/FromDcmtkBridge.h" - - -namespace Orthanc -{ - static bool DoesDicomMapMatch(const DicomMap& dicom, - const DicomTag& tag, - const IFindConstraint& constraint) - { - const DicomValue* value = dicom.TestAndGetValue(tag); - - return (value != NULL && - !value->IsNull() && - !value->IsBinary() && - constraint.Match(value->GetContent())); - } - - - LookupResource::Level::Level(ResourceType level) : level_(level) - { - const DicomTag* tags = NULL; - size_t size; - - ServerToolbox::LoadIdentifiers(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - identifiers_.insert(tags[i]); - } - - DicomMap::LoadMainDicomTags(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - if (identifiers_.find(tags[i]) == identifiers_.end()) - { - mainTags_.insert(tags[i]); - } - } - } - - LookupResource::Level::~Level() - { - for (Constraints::iterator it = mainTagsConstraints_.begin(); - it != mainTagsConstraints_.end(); ++it) - { - delete it->second; - } - - for (Constraints::iterator it = identifiersConstraints_.begin(); - it != identifiersConstraints_.end(); ++it) - { - delete it->second; - } - } - - bool LookupResource::Level::Add(const DicomTag& tag, - std::auto_ptr<IFindConstraint>& constraint) - { - if (identifiers_.find(tag) != identifiers_.end()) - { - if (level_ == ResourceType_Patient) - { - // The filters on the patient level must be cloned to the study level - identifiersConstraints_[tag] = constraint->Clone(); - } - else - { - identifiersConstraints_[tag] = constraint.release(); - } - - return true; - } - else if (mainTags_.find(tag) != mainTags_.end()) - { - if (level_ == ResourceType_Patient) - { - // The filters on the patient level must be cloned to the study level - mainTagsConstraints_[tag] = constraint->Clone(); - } - else - { - mainTagsConstraints_[tag] = constraint.release(); - } - - return true; - } - else - { - // This is not a main DICOM tag - return false; - } - } - - - bool LookupResource::Level::IsMatch(const DicomMap& dicom) const - { - for (Constraints::const_iterator it = identifiersConstraints_.begin(); - it != identifiersConstraints_.end(); ++it) - { - assert(it->second != NULL); - - if (!DoesDicomMapMatch(dicom, it->first, *it->second)) - { - return false; - } - } - - for (Constraints::const_iterator it = mainTagsConstraints_.begin(); - it != mainTagsConstraints_.end(); ++it) - { - assert(it->second != NULL); - - if (!DoesDicomMapMatch(dicom, it->first, *it->second)) - { - return false; - } - } - - return true; - } - - - LookupResource::LookupResource(ResourceType level) : level_(level) - { - switch (level) - { - case ResourceType_Patient: - levels_[ResourceType_Patient] = new Level(ResourceType_Patient); - break; - - case ResourceType_Instance: - levels_[ResourceType_Instance] = new Level(ResourceType_Instance); - // Do not add "break" here - - case ResourceType_Series: - levels_[ResourceType_Series] = new Level(ResourceType_Series); - // Do not add "break" here - - case ResourceType_Study: - levels_[ResourceType_Study] = new Level(ResourceType_Study); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - LookupResource::~LookupResource() - { - for (Levels::iterator it = levels_.begin(); - it != levels_.end(); ++it) - { - delete it->second; - } - - for (Constraints::iterator it = unoptimizedConstraints_.begin(); - it != unoptimizedConstraints_.end(); ++it) - { - delete it->second; - } - } - - - - bool LookupResource::AddInternal(ResourceType level, - const DicomTag& tag, - std::auto_ptr<IFindConstraint>& constraint) - { - Levels::iterator it = levels_.find(level); - if (it != levels_.end()) - { - if (it->second->Add(tag, constraint)) - { - return true; - } - } - - return false; - } - - - void LookupResource::Add(const DicomTag& tag, - IFindConstraint* constraint) - { - std::auto_ptr<IFindConstraint> c(constraint); - - if (!AddInternal(ResourceType_Patient, tag, c) && - !AddInternal(ResourceType_Study, tag, c) && - !AddInternal(ResourceType_Series, tag, c) && - !AddInternal(ResourceType_Instance, tag, c)) - { - unoptimizedConstraints_[tag] = c.release(); - } - } - - - static bool Match(const DicomMap& tags, - const DicomTag& tag, - const IFindConstraint& constraint) - { - const DicomValue* value = tags.TestAndGetValue(tag); - - if (value == NULL || - value->IsNull() || - value->IsBinary()) - { - return false; - } - else - { - return constraint.Match(value->GetContent()); - } - } - - - void LookupResource::Level::Apply(SetOfResources& candidates, - IDatabaseWrapper& database) const - { - // First, use the indexed identifiers - LookupIdentifierQuery query(level_); - - for (Constraints::const_iterator it = identifiersConstraints_.begin(); - it != identifiersConstraints_.end(); ++it) - { - it->second->Setup(query, it->first); - } - - query.Apply(candidates, database); - - /*{ - query.Print(std::cout); - std::list<int64_t> source; - candidates.Flatten(source); - printf("=> %d\n", source.size()); - }*/ - - // Secondly, filter using the main DICOM tags - if (!identifiersConstraints_.empty() || - !mainTagsConstraints_.empty()) - { - std::list<int64_t> source; - candidates.Flatten(source); - candidates.Clear(); - - std::list<int64_t> filtered; - for (std::list<int64_t>::const_iterator candidate = source.begin(); - candidate != source.end(); ++candidate) - { - DicomMap tags; - database.GetMainDicomTags(tags, *candidate); - - bool match = true; - - // Re-apply the identifier constraints, as their "Setup" - // method is less restrictive than their "Match" method - for (Constraints::const_iterator it = identifiersConstraints_.begin(); - match && it != identifiersConstraints_.end(); ++it) - { - if (!Match(tags, it->first, *it->second)) - { - match = false; - } - } - - for (Constraints::const_iterator it = mainTagsConstraints_.begin(); - match && it != mainTagsConstraints_.end(); ++it) - { - if (!Match(tags, it->first, *it->second)) - { - match = false; - } - } - - if (match) - { - filtered.push_back(*candidate); - } - } - - candidates.Intersect(filtered); - } - } - - - - bool LookupResource::IsMatch(const DicomMap& dicom) const - { - for (Levels::const_iterator it = levels_.begin(); it != levels_.end(); ++it) - { - if (!it->second->IsMatch(dicom)) - { - return false; - } - } - - for (Constraints::const_iterator it = unoptimizedConstraints_.begin(); - it != unoptimizedConstraints_.end(); ++it) - { - assert(it->second != NULL); - - if (!DoesDicomMapMatch(dicom, it->first, *it->second)) - { - return false; - } - } - - return true; - } - - - void LookupResource::ApplyLevel(SetOfResources& candidates, - ResourceType level, - IDatabaseWrapper& database) const - { - Levels::const_iterator it = levels_.find(level); - if (it != levels_.end()) - { - it->second->Apply(candidates, database); - } - - if (level == ResourceType_Study && - modalitiesInStudy_.get() != NULL) - { - // There is a constraint on the "ModalitiesInStudy" DICOM - // extension. Check out whether one child series has one of the - // allowed modalities - std::list<int64_t> allStudies, matchingStudies; - candidates.Flatten(allStudies); - - for (std::list<int64_t>::const_iterator - study = allStudies.begin(); study != allStudies.end(); ++study) - { - std::list<int64_t> childrenSeries; - database.GetChildrenInternalId(childrenSeries, *study); - - for (std::list<int64_t>::const_iterator - series = childrenSeries.begin(); series != childrenSeries.end(); ++series) - { - DicomMap tags; - database.GetMainDicomTags(tags, *series); - - const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY); - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - if (modalitiesInStudy_->Match(value->GetContent())) - { - matchingStudies.push_back(*study); - break; - } - } - } - } - - candidates.Intersect(matchingStudies); - } - } - - - void LookupResource::FindCandidates(std::list<int64_t>& result, - IDatabaseWrapper& database) const - { - ResourceType startingLevel; - if (level_ == ResourceType_Patient) - { - startingLevel = ResourceType_Patient; - } - else - { - startingLevel = ResourceType_Study; - } - - SetOfResources candidates(database, startingLevel); - - switch (level_) - { - case ResourceType_Patient: - ApplyLevel(candidates, ResourceType_Patient, database); - break; - - case ResourceType_Study: - ApplyLevel(candidates, ResourceType_Study, database); - break; - - case ResourceType_Series: - ApplyLevel(candidates, ResourceType_Study, database); - candidates.GoDown(); - ApplyLevel(candidates, ResourceType_Series, database); - break; - - case ResourceType_Instance: - ApplyLevel(candidates, ResourceType_Study, database); - candidates.GoDown(); - ApplyLevel(candidates, ResourceType_Series, database); - candidates.GoDown(); - ApplyLevel(candidates, ResourceType_Instance, database); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - candidates.Flatten(result); - } - - - void LookupResource::SetModalitiesInStudy(const std::string& modalities) - { - modalitiesInStudy_.reset(new ListConstraint(true /* case sensitive */)); - - std::vector<std::string> items; - Toolbox::TokenizeString(items, modalities, '\\'); - - for (size_t i = 0; i < items.size(); i++) - { - modalitiesInStudy_->AddAllowedValue(items[i]); - } - } - - - void LookupResource::AddDicomConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitive) - { - // http://www.itk.org/Wiki/DICOM_QueryRetrieve_Explained - // http://dicomiseasy.blogspot.be/2012/01/dicom-queryretrieve-part-i.html - if (tag == DICOM_TAG_MODALITIES_IN_STUDY) - { - SetModalitiesInStudy(dicomQuery); - } - else - { - Add(tag, IFindConstraint::ParseDicomConstraint(tag, dicomQuery, caseSensitive)); - } - } - -}
--- a/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupResource.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "ListConstraint.h" -#include "SetOfResources.h" - -#include <memory> - -namespace Orthanc -{ - class LookupResource : public boost::noncopyable - { - private: - typedef std::map<DicomTag, IFindConstraint*> Constraints; - - class Level - { - private: - ResourceType level_; - std::set<DicomTag> identifiers_; - std::set<DicomTag> mainTags_; - Constraints identifiersConstraints_; - Constraints mainTagsConstraints_; - - public: - Level(ResourceType level); - - ~Level(); - - bool Add(const DicomTag& tag, - std::auto_ptr<IFindConstraint>& constraint); - - void Apply(SetOfResources& candidates, - IDatabaseWrapper& database) const; - - bool IsMatch(const DicomMap& dicom) const; - }; - - typedef std::map<ResourceType, Level*> Levels; - - ResourceType level_; - Levels levels_; - Constraints unoptimizedConstraints_; // Constraints on non-main DICOM tags - std::auto_ptr<ListConstraint> modalitiesInStudy_; - - bool AddInternal(ResourceType level, - const DicomTag& tag, - std::auto_ptr<IFindConstraint>& constraint); - - void ApplyLevel(SetOfResources& candidates, - ResourceType level, - IDatabaseWrapper& database) const; - - public: - LookupResource(ResourceType level); - - ~LookupResource(); - - ResourceType GetLevel() const - { - return level_; - } - - void SetModalitiesInStudy(const std::string& modalities); - - void Add(const DicomTag& tag, - IFindConstraint* constraint); // Takes ownership - - void AddDicomConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitive); - - void FindCandidates(std::list<int64_t>& result, - IDatabaseWrapper& database) const; - - bool HasOnlyMainDicomTags() const - { - return unoptimizedConstraints_.empty(); - } - - bool IsMatch(const DicomMap& dicom) const; - }; -}
--- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(SampleDatabasePlugin) - -# Parameters of the build -SET(SAMPLE_DATABASE_VERSION "0.0" CACHE STRING "Version of the plugin") -SET(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") -SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") -SET(STANDALONE_BUILD ON) - -# Advanced parameters to fine-tune linking against system libraries -SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost") -SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp") -SET(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite") - -include(${CMAKE_SOURCE_DIR}/../../../Plugins/Samples/Common/OrthancPlugins.cmake) - -include(${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake) -set(ENABLE_SQLITE ON) -include(${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake) - -EmbedResources( - --system-exception # Use "std::runtime_error" instead of "OrthancException" for embedded resources - PREPARE_DATABASE ${CMAKE_SOURCE_DIR}/../../../Sources/Database/PrepareDatabase.sql - ) - -message("Setting the version of the plugin to ${SAMPLE_DATABASE_VERSION}") - -add_definitions( - -DORTHANC_SQLITE_STANDALONE=1 - -DORTHANC_ENABLE_PLUGINS=1 - -DORTHANC_SANDBOXED=0 - -DSAMPLE_DATABASE_VERSION="${SAMPLE_DATABASE_VERSION}" - ) - -add_library(SampleDatabase SHARED - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomArray.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomMap.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomTag.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/DicomFormat/DicomValue.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/Enumerations.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/Connection.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/FunctionContext.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/Statement.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/StatementId.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/StatementReference.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/SQLite/Transaction.cpp - ${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Sources/Toolbox.cpp - ${CMAKE_SOURCE_DIR}/../../../Plugins/Engine/PluginsEnumerations.cpp - - Database.cpp - Plugin.cpp - DatabaseWrapperBase.cpp - - ${BOOST_SOURCES} - ${JSONCPP_SOURCES} - ${SQLITE_SOURCES} - ${AUTOGENERATED_SOURCES} - ) - -set_target_properties(SampleDatabase PROPERTIES - VERSION ${SAMPLE_DATABASE_VERSION} - SOVERSION ${SAMPLE_DATABASE_VERSION}) - -install( - TARGETS SampleDatabase - RUNTIME DESTINATION lib # Destination for Windows - LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux - )
--- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/Database.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,555 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "Database.h" - -#include "../../../../OrthancFramework/Sources/DicomFormat/DicomArray.h" - -#include <EmbeddedResources.h> -#include <boost/lexical_cast.hpp> - - -namespace Internals -{ - class SignalFileDeleted : public Orthanc::SQLite::IScalarFunction - { - private: - OrthancPlugins::DatabaseBackendOutput& output_; - - public: - SignalFileDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) - { - } - - virtual const char* GetName() const - { - return "SignalFileDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 7; - } - - virtual void Compute(Orthanc::SQLite::FunctionContext& context) - { - std::string uncompressedMD5, compressedMD5; - - if (!context.IsNullValue(5)) - { - uncompressedMD5 = context.GetStringValue(5); - } - - if (!context.IsNullValue(6)) - { - compressedMD5 = context.GetStringValue(6); - } - - output_.SignalDeletedAttachment(context.GetStringValue(0), - context.GetIntValue(1), - context.GetInt64Value(2), - uncompressedMD5, - context.GetIntValue(3), - context.GetInt64Value(4), - compressedMD5); - } - }; - - - class SignalResourceDeleted : public Orthanc::SQLite::IScalarFunction - { - private: - OrthancPlugins::DatabaseBackendOutput& output_; - - public: - SignalResourceDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) - { - } - - virtual const char* GetName() const - { - return "SignalResourceDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 2; - } - - virtual void Compute(Orthanc::SQLite::FunctionContext& context) - { - output_.SignalDeletedResource(context.GetStringValue(0), - Orthanc::Plugins::Convert(static_cast<Orthanc::ResourceType>(context.GetIntValue(1)))); - } - }; -} - - -class Database::SignalRemainingAncestor : public Orthanc::SQLite::IScalarFunction -{ -private: - bool hasRemainingAncestor_; - std::string remainingPublicId_; - OrthancPluginResourceType remainingType_; - -public: - SignalRemainingAncestor() : - hasRemainingAncestor_(false), - remainingType_(OrthancPluginResourceType_Instance) // Some dummy value - { - } - - void Reset() - { - hasRemainingAncestor_ = false; - } - - virtual const char* GetName() const - { - return "SignalRemainingAncestor"; - } - - virtual unsigned int GetCardinality() const - { - return 2; - } - - virtual void Compute(Orthanc::SQLite::FunctionContext& context) - { - if (!hasRemainingAncestor_ || - remainingType_ >= context.GetIntValue(1)) - { - hasRemainingAncestor_ = true; - remainingPublicId_ = context.GetStringValue(0); - remainingType_ = Orthanc::Plugins::Convert(static_cast<Orthanc::ResourceType>(context.GetIntValue(1))); - } - } - - bool HasRemainingAncestor() const - { - return hasRemainingAncestor_; - } - - const std::string& GetRemainingAncestorId() const - { - assert(hasRemainingAncestor_); - return remainingPublicId_; - } - - OrthancPluginResourceType GetRemainingAncestorType() const - { - assert(hasRemainingAncestor_); - return remainingType_; - } -}; - - - -Database::Database(const std::string& path) : - path_(path), - base_(db_), - signalRemainingAncestor_(NULL) -{ -} - - -void Database::Open() -{ - db_.Open(path_); - - db_.Execute("PRAGMA ENCODING=\"UTF-8\";"); - - // http://www.sqlite.org/pragma.html - db_.Execute("PRAGMA SYNCHRONOUS=NORMAL;"); - db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); - db_.Execute("PRAGMA LOCKING_MODE=EXCLUSIVE;"); - db_.Execute("PRAGMA WAL_AUTOCHECKPOINT=1000;"); - //db_.Execute("PRAGMA TEMP_STORE=memory"); - - if (!db_.DoesTableExist("GlobalProperties")) - { - std::string query; - Orthanc::EmbeddedResources::GetFileResource(query, Orthanc::EmbeddedResources::PREPARE_DATABASE); - db_.Execute(query); - } - - signalRemainingAncestor_ = new SignalRemainingAncestor; - db_.Register(signalRemainingAncestor_); - db_.Register(new Internals::SignalFileDeleted(GetOutput())); - db_.Register(new Internals::SignalResourceDeleted(GetOutput())); -} - - -void Database::Close() -{ - db_.Close(); -} - - -void Database::AddAttachment(int64_t id, - const OrthancPluginAttachment& attachment) -{ - Orthanc::FileInfo info(attachment.uuid, - static_cast<Orthanc::FileContentType>(attachment.contentType), - attachment.uncompressedSize, - attachment.uncompressedHash, - static_cast<Orthanc::CompressionType>(attachment.compressionType), - attachment.compressedSize, - attachment.compressedHash); - base_.AddAttachment(id, info); -} - - -void Database::DeleteResource(int64_t id) -{ - signalRemainingAncestor_->Reset(); - - Orthanc::SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Resources WHERE internalId=?"); - s.BindInt64(0, id); - s.Run(); - - if (signalRemainingAncestor_->HasRemainingAncestor()) - { - GetOutput().SignalRemainingAncestor(signalRemainingAncestor_->GetRemainingAncestorId(), - signalRemainingAncestor_->GetRemainingAncestorType()); - } -} - - -static void Answer(OrthancPlugins::DatabaseBackendOutput& output, - const Orthanc::ServerIndexChange& change) -{ - output.AnswerChange(change.GetSeq(), - change.GetChangeType(), - Orthanc::Plugins::Convert(change.GetResourceType()), - change.GetPublicId(), - change.GetDate()); -} - - -static void Answer(OrthancPlugins::DatabaseBackendOutput& output, - const Orthanc::ExportedResource& resource) -{ - output.AnswerExportedResource(resource.GetSeq(), - Orthanc::Plugins::Convert(resource.GetResourceType()), - resource.GetPublicId(), - resource.GetModality(), - resource.GetDate(), - resource.GetPatientId(), - resource.GetStudyInstanceUid(), - resource.GetSeriesInstanceUid(), - resource.GetSopInstanceUid()); -} - - -void Database::GetChanges(bool& done /*out*/, - int64_t since, - uint32_t maxResults) -{ - typedef std::list<Orthanc::ServerIndexChange> Changes; - - Changes changes; - base_.GetChanges(changes, done, since, maxResults); - - for (Changes::const_iterator it = changes.begin(); it != changes.end(); ++it) - { - Answer(GetOutput(), *it); - } -} - - -void Database::GetExportedResources(bool& done /*out*/, - int64_t since, - uint32_t maxResults) -{ - typedef std::list<Orthanc::ExportedResource> Resources; - - Resources resources; - base_.GetExportedResources(resources, done, since, maxResults); - - for (Resources::const_iterator it = resources.begin(); it != resources.end(); ++it) - { - Answer(GetOutput(), *it); - } -} - - -void Database::GetLastChange() -{ - std::list<Orthanc::ServerIndexChange> change; - Orthanc::ErrorCode code = base_.GetLastChange(change); - - if (code != Orthanc::ErrorCode_Success) - { - throw OrthancPlugins::DatabaseException(static_cast<OrthancPluginErrorCode>(code)); - } - - if (!change.empty()) - { - Answer(GetOutput(), change.front()); - } -} - - -void Database::GetLastExportedResource() -{ - std::list<Orthanc::ExportedResource> resource; - base_.GetLastExportedResource(resource); - - if (!resource.empty()) - { - Answer(GetOutput(), resource.front()); - } -} - - -void Database::GetMainDicomTags(int64_t id) -{ - Orthanc::DicomMap tags; - base_.GetMainDicomTags(tags, id); - - Orthanc::DicomArray arr(tags); - for (size_t i = 0; i < arr.GetSize(); i++) - { - GetOutput().AnswerDicomTag(arr.GetElement(i).GetTag().GetGroup(), - arr.GetElement(i).GetTag().GetElement(), - arr.GetElement(i).GetValue().GetContent()); - } -} - - -std::string Database::GetPublicId(int64_t resourceId) -{ - std::string id; - if (base_.GetPublicId(id, resourceId)) - { - return id; - } - else - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_UnknownResource); - } -} - - -OrthancPluginResourceType Database::GetResourceType(int64_t resourceId) -{ - Orthanc::ResourceType result; - Orthanc::ErrorCode code = base_.GetResourceType(result, resourceId); - - if (code == Orthanc::ErrorCode_Success) - { - return Orthanc::Plugins::Convert(result); - } - else - { - throw OrthancPlugins::DatabaseException(static_cast<OrthancPluginErrorCode>(code)); - } -} - - - -template <typename I> -static void ConvertList(std::list<int32_t>& target, - const std::list<I>& source) -{ - for (typename std::list<I>::const_iterator - it = source.begin(); it != source.end(); ++it) - { - target.push_back(*it); - } -} - - -void Database::ListAvailableMetadata(std::list<int32_t>& target /*out*/, - int64_t id) -{ - std::list<Orthanc::MetadataType> tmp; - base_.ListAvailableMetadata(tmp, id); - ConvertList(target, tmp); -} - - -void Database::ListAvailableAttachments(std::list<int32_t>& target /*out*/, - int64_t id) -{ - std::list<Orthanc::FileContentType> tmp; - base_.ListAvailableAttachments(tmp, id); - ConvertList(target, tmp); -} - - -void Database::LogChange(const OrthancPluginChange& change) -{ - int64_t id; - OrthancPluginResourceType type; - if (!LookupResource(id, type, change.publicId) || - type != change.resourceType) - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_DatabasePlugin); - } - - Orthanc::ServerIndexChange tmp(change.seq, - static_cast<Orthanc::ChangeType>(change.changeType), - Orthanc::Plugins::Convert(change.resourceType), - change.publicId, - change.date); - - base_.LogChange(id, tmp); -} - - -void Database::LogExportedResource(const OrthancPluginExportedResource& resource) -{ - Orthanc::ExportedResource tmp(resource.seq, - Orthanc::Plugins::Convert(resource.resourceType), - resource.publicId, - resource.modality, - resource.date, - resource.patientId, - resource.studyInstanceUid, - resource.seriesInstanceUid, - resource.sopInstanceUid); - - base_.LogExportedResource(tmp); -} - - -bool Database::LookupAttachment(int64_t id, - int32_t contentType) -{ - Orthanc::FileInfo attachment; - if (base_.LookupAttachment(attachment, id, static_cast<Orthanc::FileContentType>(contentType))) - { - GetOutput().AnswerAttachment(attachment.GetUuid(), - attachment.GetContentType(), - attachment.GetUncompressedSize(), - attachment.GetUncompressedMD5(), - attachment.GetCompressionType(), - attachment.GetCompressedSize(), - attachment.GetCompressedMD5()); - return true; - } - else - { - return false; - } -} - - -bool Database::LookupParent(int64_t& parentId /*out*/, - int64_t resourceId) -{ - bool found; - Orthanc::ErrorCode code = base_.LookupParent(found, parentId, resourceId); - - if (code == Orthanc::ErrorCode_Success) - { - return found; - } - else - { - throw OrthancPlugins::DatabaseException(static_cast<OrthancPluginErrorCode>(code)); - } -} - - -bool Database::LookupResource(int64_t& id /*out*/, - OrthancPluginResourceType& type /*out*/, - const char* publicId) -{ - Orthanc::ResourceType tmp; - if (base_.LookupResource(id, tmp, publicId)) - { - type = Orthanc::Plugins::Convert(tmp); - return true; - } - else - { - return false; - } -} - - -void Database::StartTransaction() -{ - transaction_.reset(new Orthanc::SQLite::Transaction(db_)); - transaction_->Begin(); -} - - -void Database::RollbackTransaction() -{ - transaction_->Rollback(); - transaction_.reset(NULL); -} - - -void Database::CommitTransaction() -{ - transaction_->Commit(); - transaction_.reset(NULL); -} - - -uint32_t Database::GetDatabaseVersion() -{ - std::string version; - - if (!LookupGlobalProperty(version, Orthanc::GlobalProperty_DatabaseSchemaVersion)) - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_InternalError); - } - - try - { - return boost::lexical_cast<uint32_t>(version); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_InternalError); - } -} - - -void Database::UpgradeDatabase(uint32_t targetVersion, - OrthancPluginStorageArea* storageArea) -{ - if (targetVersion == 6) - { - OrthancPluginErrorCode code = OrthancPluginReconstructMainDicomTags(GetOutput().GetContext(), storageArea, - OrthancPluginResourceType_Study); - if (code == OrthancPluginErrorCode_Success) - { - code = OrthancPluginReconstructMainDicomTags(GetOutput().GetContext(), storageArea, - OrthancPluginResourceType_Series); - } - - if (code != OrthancPluginErrorCode_Success) - { - throw OrthancPlugins::DatabaseException(code); - } - - base_.SetGlobalProperty(Orthanc::GlobalProperty_DatabaseSchemaVersion, "6"); - } -}
--- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/Database.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "OrthancCppDatabasePlugin.h" - -#include "../../../../OrthancFramework/Sources/SQLite/Connection.h" -#include "../../../../OrthancFramework/Sources/SQLite/Transaction.h" -#include "../../../Plugins/Engine/PluginsEnumerations.h" -#include "DatabaseWrapperBase.h" - -#include <memory> - -class Database : public OrthancPlugins::IDatabaseBackend -{ -private: - class SignalRemainingAncestor; - - std::string path_; - Orthanc::SQLite::Connection db_; - Orthanc::DatabaseWrapperBase base_; - SignalRemainingAncestor* signalRemainingAncestor_; - - std::auto_ptr<Orthanc::SQLite::Transaction> transaction_; - -public: - Database(const std::string& path); - - virtual void Open(); - - virtual void Close(); - - virtual void AddAttachment(int64_t id, - const OrthancPluginAttachment& attachment); - - virtual void AttachChild(int64_t parent, - int64_t child) - { - base_.AttachChild(parent, child); - } - - virtual void ClearChanges() - { - db_.Execute("DELETE FROM Changes"); - } - - virtual void ClearExportedResources() - { - db_.Execute("DELETE FROM ExportedResources"); - } - - virtual int64_t CreateResource(const char* publicId, - OrthancPluginResourceType type) - { - return base_.CreateResource(publicId, Orthanc::Plugins::Convert(type)); - } - - virtual void DeleteAttachment(int64_t id, - int32_t attachment) - { - base_.DeleteAttachment(id, static_cast<Orthanc::FileContentType>(attachment)); - } - - virtual void DeleteMetadata(int64_t id, - int32_t metadataType) - { - base_.DeleteMetadata(id, static_cast<Orthanc::MetadataType>(metadataType)); - } - - virtual void DeleteResource(int64_t id); - - virtual void GetAllInternalIds(std::list<int64_t>& target, - OrthancPluginResourceType resourceType) - { - base_.GetAllInternalIds(target, Orthanc::Plugins::Convert(resourceType)); - } - - virtual void GetAllPublicIds(std::list<std::string>& target, - OrthancPluginResourceType resourceType) - { - base_.GetAllPublicIds(target, Orthanc::Plugins::Convert(resourceType)); - } - - virtual void GetAllPublicIds(std::list<std::string>& target, - OrthancPluginResourceType resourceType, - uint64_t since, - uint64_t limit) - { - base_.GetAllPublicIds(target, Orthanc::Plugins::Convert(resourceType), since, limit); - } - - virtual void GetChanges(bool& done /*out*/, - int64_t since, - uint32_t maxResults); - - virtual void GetChildrenInternalId(std::list<int64_t>& target /*out*/, - int64_t id) - { - base_.GetChildrenInternalId(target, id); - } - - virtual void GetChildrenPublicId(std::list<std::string>& target /*out*/, - int64_t id) - { - base_.GetChildrenPublicId(target, id); - } - - virtual void GetExportedResources(bool& done /*out*/, - int64_t since, - uint32_t maxResults); - - virtual void GetLastChange(); - - virtual void GetLastExportedResource(); - - virtual void GetMainDicomTags(int64_t id); - - virtual std::string GetPublicId(int64_t resourceId); - - virtual uint64_t GetResourceCount(OrthancPluginResourceType resourceType) - { - return base_.GetResourceCount(Orthanc::Plugins::Convert(resourceType)); - } - - virtual OrthancPluginResourceType GetResourceType(int64_t resourceId); - - virtual uint64_t GetTotalCompressedSize() - { - return base_.GetTotalCompressedSize(); - } - - virtual uint64_t GetTotalUncompressedSize() - { - return base_.GetTotalUncompressedSize(); - } - - virtual bool IsExistingResource(int64_t internalId) - { - return base_.IsExistingResource(internalId); - } - - virtual bool IsProtectedPatient(int64_t internalId) - { - return base_.IsProtectedPatient(internalId); - } - - virtual void ListAvailableMetadata(std::list<int32_t>& target /*out*/, - int64_t id); - - virtual void ListAvailableAttachments(std::list<int32_t>& target /*out*/, - int64_t id); - - virtual void LogChange(const OrthancPluginChange& change); - - virtual void LogExportedResource(const OrthancPluginExportedResource& resource); - - virtual bool LookupAttachment(int64_t id, - int32_t contentType); - - virtual bool LookupGlobalProperty(std::string& target /*out*/, - int32_t property) - { - return base_.LookupGlobalProperty(target, static_cast<Orthanc::GlobalProperty>(property)); - } - - virtual void LookupIdentifier(std::list<int64_t>& target /*out*/, - OrthancPluginResourceType level, - uint16_t group, - uint16_t element, - OrthancPluginIdentifierConstraint constraint, - const char* value) - { - base_.LookupIdentifier(target, Orthanc::Plugins::Convert(level), - Orthanc::DicomTag(group, element), - Orthanc::Plugins::Convert(constraint), value); - } - - virtual bool LookupMetadata(std::string& target /*out*/, - int64_t id, - int32_t metadataType) - { - return base_.LookupMetadata(target, id, static_cast<Orthanc::MetadataType>(metadataType)); - } - - virtual bool LookupParent(int64_t& parentId /*out*/, - int64_t resourceId); - - virtual bool LookupResource(int64_t& id /*out*/, - OrthancPluginResourceType& type /*out*/, - const char* publicId); - - virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/) - { - return base_.SelectPatientToRecycle(internalId); - } - - virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/, - int64_t patientIdToAvoid) - { - return base_.SelectPatientToRecycle(internalId, patientIdToAvoid); - } - - - virtual void SetGlobalProperty(int32_t property, - const char* value) - { - base_.SetGlobalProperty(static_cast<Orthanc::GlobalProperty>(property), value); - } - - virtual void SetMainDicomTag(int64_t id, - uint16_t group, - uint16_t element, - const char* value) - { - base_.SetMainDicomTag(id, Orthanc::DicomTag(group, element), value); - } - - virtual void SetIdentifierTag(int64_t id, - uint16_t group, - uint16_t element, - const char* value) - { - base_.SetIdentifierTag(id, Orthanc::DicomTag(group, element), value); - } - - virtual void SetMetadata(int64_t id, - int32_t metadataType, - const char* value) - { - base_.SetMetadata(id, static_cast<Orthanc::MetadataType>(metadataType), value); - } - - virtual void SetProtectedPatient(int64_t internalId, - bool isProtected) - { - base_.SetProtectedPatient(internalId, isProtected); - } - - virtual void StartTransaction(); - - virtual void RollbackTransaction(); - - virtual void CommitTransaction(); - - virtual uint32_t GetDatabaseVersion(); - - virtual void UpgradeDatabase(uint32_t targetVersion, - OrthancPluginStorageArea* storageArea); - - virtual void ClearMainDicomTags(int64_t internalId) - { - base_.ClearMainDicomTags(internalId); - } -};
--- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,747 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../../../Sources/PrecompiledHeadersServer.h" -#include "DatabaseWrapperBase.h" - -#include <stdio.h> -#include <memory> - -namespace Orthanc -{ - void DatabaseWrapperBase::SetGlobalProperty(GlobalProperty property, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO GlobalProperties VALUES(?, ?)"); - s.BindInt(0, property); - s.BindString(1, value); - s.Run(); - } - - bool DatabaseWrapperBase::LookupGlobalProperty(std::string& target, - GlobalProperty property) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM GlobalProperties WHERE property=?"); - s.BindInt(0, property); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - int64_t DatabaseWrapperBase::CreateResource(const std::string& publicId, - ResourceType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Resources VALUES(NULL, ?, ?, NULL)"); - s.BindInt(0, type); - s.BindString(1, publicId); - s.Run(); - return db_.GetLastInsertRowId(); - } - - bool DatabaseWrapperBase::LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT internalId, resourceType FROM Resources WHERE publicId=?"); - s.BindString(0, publicId); - - if (!s.Step()) - { - return false; - } - else - { - id = s.ColumnInt(0); - type = static_cast<ResourceType>(s.ColumnInt(1)); - - // Check whether there is a single resource with this public id - assert(!s.Step()); - - return true; - } - } - - ErrorCode DatabaseWrapperBase::LookupParent(bool& found, - int64_t& parentId, - int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT parentId FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (!s.Step()) - { - return ErrorCode_UnknownResource; - } - - if (s.ColumnIsNull(0)) - { - found = false; - } - else - { - found = true; - parentId = s.ColumnInt(0); - } - - return ErrorCode_Success; - } - - bool DatabaseWrapperBase::GetPublicId(std::string& result, - int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT publicId FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (!s.Step()) - { - return false; - } - else - { - result = s.ColumnString(0); - return true; - } - } - - - ErrorCode DatabaseWrapperBase::GetResourceType(ResourceType& result, - int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT resourceType FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (s.Step()) - { - result = static_cast<ResourceType>(s.ColumnInt(0)); - return ErrorCode_Success; - } - else - { - return ErrorCode_UnknownResource; - } - } - - - void DatabaseWrapperBase::AttachChild(int64_t parent, - int64_t child) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "UPDATE Resources SET parentId = ? WHERE internalId = ?"); - s.BindInt64(0, parent); - s.BindInt64(1, child); - s.Run(); - } - - - void DatabaseWrapperBase::SetMetadata(int64_t id, - MetadataType type, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO Metadata VALUES(?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, type); - s.BindString(2, value); - s.Run(); - } - - void DatabaseWrapperBase::DeleteMetadata(int64_t id, - MetadataType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Metadata WHERE id=? and type=?"); - s.BindInt64(0, id); - s.BindInt(1, type); - s.Run(); - } - - bool DatabaseWrapperBase::LookupMetadata(std::string& target, - int64_t id, - MetadataType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM Metadata WHERE id=? AND type=?"); - s.BindInt64(0, id); - s.BindInt(1, type); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - void DatabaseWrapperBase::ListAvailableMetadata(std::list<MetadataType>& target, - int64_t id) - { - target.clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT type FROM Metadata WHERE id=?"); - s.BindInt64(0, id); - - while (s.Step()) - { - target.push_back(static_cast<MetadataType>(s.ColumnInt(0))); - } - } - - - void DatabaseWrapperBase::AddAttachment(int64_t id, - const FileInfo& attachment) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, attachment.GetContentType()); - s.BindString(2, attachment.GetUuid()); - s.BindInt64(3, attachment.GetCompressedSize()); - s.BindInt64(4, attachment.GetUncompressedSize()); - s.BindInt(5, attachment.GetCompressionType()); - s.BindString(6, attachment.GetUncompressedMD5()); - s.BindString(7, attachment.GetCompressedMD5()); - s.Run(); - } - - - void DatabaseWrapperBase::DeleteAttachment(int64_t id, - FileContentType attachment) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM AttachedFiles WHERE id=? AND fileType=?"); - s.BindInt64(0, id); - s.BindInt(1, attachment); - s.Run(); - } - - - - void DatabaseWrapperBase::ListAvailableAttachments(std::list<FileContentType>& target, - int64_t id) - { - target.clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT fileType FROM AttachedFiles WHERE id=?"); - s.BindInt64(0, id); - - while (s.Step()) - { - target.push_back(static_cast<FileContentType>(s.ColumnInt(0))); - } - } - - bool DatabaseWrapperBase::LookupAttachment(FileInfo& attachment, - int64_t id, - FileContentType contentType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT uuid, uncompressedSize, compressionType, compressedSize, uncompressedMD5, compressedMD5 FROM AttachedFiles WHERE id=? AND fileType=?"); - s.BindInt64(0, id); - s.BindInt(1, contentType); - - if (!s.Step()) - { - return false; - } - else - { - attachment = FileInfo(s.ColumnString(0), - contentType, - s.ColumnInt64(1), - s.ColumnString(4), - static_cast<CompressionType>(s.ColumnInt(2)), - s.ColumnInt64(3), - s.ColumnString(5)); - return true; - } - } - - - void DatabaseWrapperBase::ClearMainDicomTags(int64_t id) - { - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM DicomIdentifiers WHERE id=?"); - s.BindInt64(0, id); - s.Run(); - } - - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM MainDicomTags WHERE id=?"); - s.BindInt64(0, id); - s.Run(); - } - } - - - void DatabaseWrapperBase::SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, tag.GetGroup()); - s.BindInt(2, tag.GetElement()); - s.BindString(3, value); - s.Run(); - } - - - void DatabaseWrapperBase::SetIdentifierTag(int64_t id, - const DicomTag& tag, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO DicomIdentifiers VALUES(?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, tag.GetGroup()); - s.BindInt(2, tag.GetElement()); - s.BindString(3, value); - s.Run(); - } - - - void DatabaseWrapperBase::GetMainDicomTags(DicomMap& map, - int64_t id) - { - map.Clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM MainDicomTags WHERE id=?"); - s.BindInt64(0, id); - while (s.Step()) - { - map.SetValue(s.ColumnInt(1), - s.ColumnInt(2), - s.ColumnString(3), false); - } - } - - - - void DatabaseWrapperBase::GetChildrenPublicId(std::list<std::string>& target, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b " - "WHERE a.parentId = b.internalId AND b.internalId = ?"); - s.BindInt64(0, id); - - target.clear(); - - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - - void DatabaseWrapperBase::GetChildrenInternalId(std::list<int64_t>& target, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.internalId FROM Resources AS a, Resources AS b " - "WHERE a.parentId = b.internalId AND b.internalId = ?"); - s.BindInt64(0, id); - - target.clear(); - - while (s.Step()) - { - target.push_back(s.ColumnInt64(0)); - } - } - - - void DatabaseWrapperBase::LogChange(int64_t internalId, - const ServerIndexChange& change) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Changes VALUES(NULL, ?, ?, ?, ?)"); - s.BindInt(0, change.GetChangeType()); - s.BindInt64(1, internalId); - s.BindInt(2, change.GetResourceType()); - s.BindString(3, change.GetDate()); - s.Run(); - } - - - ErrorCode DatabaseWrapperBase::GetChangesInternal(std::list<ServerIndexChange>& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults) - { - target.clear(); - - while (target.size() < maxResults && s.Step()) - { - int64_t seq = s.ColumnInt64(0); - ChangeType changeType = static_cast<ChangeType>(s.ColumnInt(1)); - ResourceType resourceType = static_cast<ResourceType>(s.ColumnInt(3)); - const std::string& date = s.ColumnString(4); - - int64_t internalId = s.ColumnInt64(2); - std::string publicId; - if (!GetPublicId(publicId, internalId)) - { - return ErrorCode_UnknownResource; - } - - target.push_back(ServerIndexChange(seq, changeType, resourceType, publicId, date)); - } - - done = !(target.size() == maxResults && s.Step()); - return ErrorCode_Success; - } - - - ErrorCode DatabaseWrapperBase::GetChanges(std::list<ServerIndexChange>& target, - bool& done, - int64_t since, - uint32_t maxResults) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes WHERE seq>? ORDER BY seq LIMIT ?"); - s.BindInt64(0, since); - s.BindInt(1, maxResults + 1); - return GetChangesInternal(target, done, s, maxResults); - } - - ErrorCode DatabaseWrapperBase::GetLastChange(std::list<ServerIndexChange>& target) - { - bool done; // Ignored - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1"); - return GetChangesInternal(target, done, s, 1); - } - - - void DatabaseWrapperBase::LogExportedResource(const ExportedResource& resource) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "INSERT INTO ExportedResources VALUES(NULL, ?, ?, ?, ?, ?, ?, ?, ?)"); - - s.BindInt(0, resource.GetResourceType()); - s.BindString(1, resource.GetPublicId()); - s.BindString(2, resource.GetModality()); - s.BindString(3, resource.GetPatientId()); - s.BindString(4, resource.GetStudyInstanceUid()); - s.BindString(5, resource.GetSeriesInstanceUid()); - s.BindString(6, resource.GetSopInstanceUid()); - s.BindString(7, resource.GetDate()); - s.Run(); - } - - - void DatabaseWrapperBase::GetExportedResourcesInternal(std::list<ExportedResource>& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults) - { - target.clear(); - - while (target.size() < maxResults && s.Step()) - { - int64_t seq = s.ColumnInt64(0); - ResourceType resourceType = static_cast<ResourceType>(s.ColumnInt(1)); - std::string publicId = s.ColumnString(2); - - ExportedResource resource(seq, - resourceType, - publicId, - s.ColumnString(3), // modality - s.ColumnString(8), // date - s.ColumnString(4), // patient ID - s.ColumnString(5), // study instance UID - s.ColumnString(6), // series instance UID - s.ColumnString(7)); // sop instance UID - - target.push_back(resource); - } - - done = !(target.size() == maxResults && s.Step()); - } - - - void DatabaseWrapperBase::GetExportedResources(std::list<ExportedResource>& target, - bool& done, - int64_t since, - uint32_t maxResults) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM ExportedResources WHERE seq>? ORDER BY seq LIMIT ?"); - s.BindInt64(0, since); - s.BindInt(1, maxResults + 1); - GetExportedResourcesInternal(target, done, s, maxResults); - } - - - void DatabaseWrapperBase::GetLastExportedResource(std::list<ExportedResource>& target) - { - bool done; // Ignored - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM ExportedResources ORDER BY seq DESC LIMIT 1"); - GetExportedResourcesInternal(target, done, s, 1); - } - - - - uint64_t DatabaseWrapperBase::GetTotalCompressedSize() - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(compressedSize) FROM AttachedFiles"); - s.Run(); - return static_cast<uint64_t>(s.ColumnInt64(0)); - } - - - uint64_t DatabaseWrapperBase::GetTotalUncompressedSize() - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(uncompressedSize) FROM AttachedFiles"); - s.Run(); - return static_cast<uint64_t>(s.ColumnInt64(0)); - } - - void DatabaseWrapperBase::GetAllInternalIds(std::list<int64_t>& target, - ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT internalId FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnInt64(0)); - } - } - - - void DatabaseWrapperBase::GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - void DatabaseWrapperBase::GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - size_t since, - size_t limit) - { - if (limit == 0) - { - target.clear(); - return; - } - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE resourceType=? LIMIT ? OFFSET ?"); - s.BindInt(0, resourceType); - s.BindInt64(1, limit); - s.BindInt64(2, since); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - - uint64_t DatabaseWrapperBase::GetResourceCount(ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT COUNT(*) FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - if (!s.Step()) - { - return 0; - } - else - { - int64_t c = s.ColumnInt(0); - assert(!s.Step()); - return c; - } - } - - - bool DatabaseWrapperBase::SelectPatientToRecycle(int64_t& internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT patientId FROM PatientRecyclingOrder ORDER BY seq ASC LIMIT 1"); - - if (!s.Step()) - { - // No patient remaining or all the patients are protected - return false; - } - else - { - internalId = s.ColumnInt(0); - return true; - } - } - - bool DatabaseWrapperBase::SelectPatientToRecycle(int64_t& internalId, - int64_t patientIdToAvoid) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT patientId FROM PatientRecyclingOrder " - "WHERE patientId != ? ORDER BY seq ASC LIMIT 1"); - s.BindInt64(0, patientIdToAvoid); - - if (!s.Step()) - { - // No patient remaining or all the patients are protected - return false; - } - else - { - internalId = s.ColumnInt(0); - return true; - } - } - - bool DatabaseWrapperBase::IsProtectedPatient(int64_t internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM PatientRecyclingOrder WHERE patientId = ?"); - s.BindInt64(0, internalId); - return !s.Step(); - } - - void DatabaseWrapperBase::SetProtectedPatient(int64_t internalId, - bool isProtected) - { - if (isProtected) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM PatientRecyclingOrder WHERE patientId=?"); - s.BindInt64(0, internalId); - s.Run(); - } - else if (IsProtectedPatient(internalId)) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO PatientRecyclingOrder VALUES(NULL, ?)"); - s.BindInt64(0, internalId); - s.Run(); - } - else - { - // Nothing to do: The patient is already unprotected - } - } - - - - bool DatabaseWrapperBase::IsExistingResource(int64_t internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM Resources WHERE internalId=?"); - s.BindInt64(0, internalId); - return s.Step(); - } - - - - void DatabaseWrapperBase::LookupIdentifier(std::list<int64_t>& target, - ResourceType level, - const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value) - { - static const char* COMMON = ("SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE " - "d.id = r.internalId AND r.resourceType=? AND " - "d.tagGroup=? AND d.tagElement=? AND "); - - std::auto_ptr<SQLite::Statement> s; - - switch (type) - { - case IdentifierConstraintType_GreaterOrEqual: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value>=?")); - break; - - case IdentifierConstraintType_SmallerOrEqual: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value<=?")); - break; - - case IdentifierConstraintType_Wildcard: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value GLOB ?")); - break; - - case IdentifierConstraintType_Equal: - default: - s.reset(new SQLite::Statement(db_, std::string(COMMON) + "d.value=?")); - break; - } - - assert(s.get() != NULL); - - s->BindInt(0, level); - s->BindInt(1, tag.GetGroup()); - s->BindInt(2, tag.GetElement()); - s->BindString(3, value); - - target.clear(); - - while (s->Step()) - { - target.push_back(s->ColumnInt64(0)); - } - } - - - void DatabaseWrapperBase::LookupIdentifierRange(std::list<int64_t>& target, - ResourceType level, - const DicomTag& tag, - const std::string& start, - const std::string& end) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE " - "d.id = r.internalId AND r.resourceType=? AND " - "d.tagGroup=? AND d.tagElement=? AND d.value>=? AND d.value<=?"); - - statement.BindInt(0, level); - statement.BindInt(1, tag.GetGroup()); - statement.BindInt(2, tag.GetElement()); - statement.BindString(3, start); - statement.BindString(4, end); - - target.clear(); - - while (statement.Step()) - { - target.push_back(statement.ColumnInt64(0)); - } - } -}
--- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/DatabaseWrapperBase.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" -#include "../../../../OrthancFramework/Sources/DicomFormat/DicomTag.h" -#include "../../../../OrthancFramework/Sources/Enumerations.h" -#include "../../../../OrthancFramework/Sources/FileStorage/FileInfo.h" -#include "../../../../OrthancFramework/Sources/SQLite/Connection.h" -#include "../../../Sources/ExportedResource.h" -#include "../../../Sources/ServerIndexChange.h" -#include "../../../Sources/ServerEnumerations.h" - -#include <list> - - -namespace Orthanc -{ - /** - * This class is shared between the Orthanc core and the sample - * database plugin whose code is in - * "../Plugins/Samples/DatabasePlugin". - **/ - class DatabaseWrapperBase - { - private: - SQLite::Connection& db_; - - ErrorCode GetChangesInternal(std::list<ServerIndexChange>& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults); - - void GetExportedResourcesInternal(std::list<ExportedResource>& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults); - - public: - DatabaseWrapperBase(SQLite::Connection& db) : db_(db) - { - } - - void SetGlobalProperty(GlobalProperty property, - const std::string& value); - - bool LookupGlobalProperty(std::string& target, - GlobalProperty property); - - int64_t CreateResource(const std::string& publicId, - ResourceType type); - - bool LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId); - - ErrorCode LookupParent(bool& found, - int64_t& parentId, - int64_t resourceId); - - bool GetPublicId(std::string& result, - int64_t resourceId); - - ErrorCode GetResourceType(ResourceType& result, - int64_t resourceId); - - void AttachChild(int64_t parent, - int64_t child); - - void SetMetadata(int64_t id, - MetadataType type, - const std::string& value); - - void DeleteMetadata(int64_t id, - MetadataType type); - - bool LookupMetadata(std::string& target, - int64_t id, - MetadataType type); - - void ListAvailableMetadata(std::list<MetadataType>& target, - int64_t id); - - void AddAttachment(int64_t id, - const FileInfo& attachment); - - void DeleteAttachment(int64_t id, - FileContentType attachment); - - void ListAvailableAttachments(std::list<FileContentType>& target, - int64_t id); - - bool LookupAttachment(FileInfo& attachment, - int64_t id, - FileContentType contentType); - - - void ClearMainDicomTags(int64_t id); - - - void SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value); - - void SetIdentifierTag(int64_t id, - const DicomTag& tag, - const std::string& value); - - void GetMainDicomTags(DicomMap& map, - int64_t id); - - void GetChildrenPublicId(std::list<std::string>& target, - int64_t id); - - void GetChildrenInternalId(std::list<int64_t>& target, - int64_t id); - - void LogChange(int64_t internalId, - const ServerIndexChange& change); - - ErrorCode GetChanges(std::list<ServerIndexChange>& target, - bool& done, - int64_t since, - uint32_t maxResults); - - ErrorCode GetLastChange(std::list<ServerIndexChange>& target); - - void LogExportedResource(const ExportedResource& resource); - - void GetExportedResources(std::list<ExportedResource>& target, - bool& done, - int64_t since, - uint32_t maxResults); - - void GetLastExportedResource(std::list<ExportedResource>& target); - - uint64_t GetTotalCompressedSize(); - - uint64_t GetTotalUncompressedSize(); - - void GetAllInternalIds(std::list<int64_t>& target, - ResourceType resourceType); - - void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType); - - void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - size_t since, - size_t limit); - - uint64_t GetResourceCount(ResourceType resourceType); - - bool SelectPatientToRecycle(int64_t& internalId); - - bool SelectPatientToRecycle(int64_t& internalId, - int64_t patientIdToAvoid); - - bool IsProtectedPatient(int64_t internalId); - - void SetProtectedPatient(int64_t internalId, - bool isProtected); - - bool IsExistingResource(int64_t internalId); - - void LookupIdentifier(std::list<int64_t>& result, - ResourceType level, - const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value); - - void LookupIdentifierRange(std::list<int64_t>& result, - ResourceType level, - const DicomTag& tag, - const std::string& start, - const std::string& end); - }; -} -
--- a/OrthancServer/Resources/Graveyard/DatabasePluginSample/Plugin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "Database.h" - -#include <memory> -#include <iostream> -#include <boost/algorithm/string/predicate.hpp> - -static OrthancPluginContext* context_ = NULL; -static std::auto_ptr<OrthancPlugins::IDatabaseBackend> backend_; - - -extern "C" -{ - ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) - { - context_ = c; - OrthancPluginLogWarning(context_, "Sample plugin is initializing"); - - /* Check the version of the Orthanc core */ - if (OrthancPluginCheckVersion(c) == 0) - { - char info[256]; - sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", - c->orthancVersion, - ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, - ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, - ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); - OrthancPluginLogError(context_, info); - return -1; - } - - std::string path = "SampleDatabase.sqlite"; - uint32_t argCount = OrthancPluginGetCommandLineArgumentsCount(context_); - for (uint32_t i = 0; i < argCount; i++) - { - char* tmp = OrthancPluginGetCommandLineArgument(context_, i); - std::string argument(tmp); - OrthancPluginFreeString(context_, tmp); - - if (boost::starts_with(argument, "--database=")) - { - path = argument.substr(11); - } - } - - std::string s = "Using the following SQLite database: " + path; - OrthancPluginLogWarning(context_, s.c_str()); - - backend_.reset(new Database(path)); - OrthancPlugins::DatabaseBackendAdapter::Register(context_, *backend_); - - return 0; - } - - ORTHANC_PLUGINS_API void OrthancPluginFinalize() - { - backend_.reset(NULL); - } - - ORTHANC_PLUGINS_API const char* OrthancPluginGetName() - { - return "sample-database"; - } - - - ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() - { - return "1.0"; - } -}
--- a/OrthancServer/Resources/Graveyard/FindRefactoringForSQLite.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -#if 0 - // TODO-FIND: Remove this implementation, as it should be done by - // the compatibility mode implemented by "GenericFind" - - virtual void ExecuteFind(FindResponse& response, - const FindRequest& request, - const std::vector<DatabaseConstraint>& normalized) ORTHANC_OVERRIDE - { -#if 0 - Compatibility::GenericFind find(*this); - find.Execute(response, request); -#else - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS FilteredResourcesIds"); - s.Run(); - } - - { - - LookupFormatter formatter; - - std::string sqlLookup; - LookupFormatter::Apply(sqlLookup, - formatter, - normalized, - request.GetLevel(), - request.GetLabels(), - request.GetLabelsConstraint(), - (request.HasLimits() ? request.GetLimitsCount() : 0)); // TODO: handles since and count - - { - // first create a temporary table that with the filtered and ordered results - sqlLookup = "CREATE TEMPORARY TABLE FilteredResourcesIds AS " + sqlLookup; - - SQLite::Statement statement(db_, SQLITE_FROM_HERE_DYNAMIC(sqlLookup), sqlLookup); - formatter.Bind(statement); - statement.Run(); - } - - { - // create the response item with the public ids only - SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT publicId FROM FilteredResourcesIds"); - formatter.Bind(statement); - - while (statement.Step()) - { - const std::string resourceId = statement.ColumnString(0); - response.Add(new FindResponse::Resource(request.GetLevel(), resourceId)); - } - } - - // request Each response content through INNER JOIN with the temporary table - if (request.IsRetrieveMainDicomTags()) - { - // TODO-FIND: handle the case where we request tags from multiple levels - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT publicId, tagGroup, tagElement, value FROM MainDicomTags AS tags " - " INNER JOIN FilteredResourcesIds ON tags.id = FilteredResourcesIds.internalId"); - formatter.Bind(statement); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddStringDicomTag(statement.ColumnInt(1), - statement.ColumnInt(2), - statement.ColumnString(3)); - } - } - - if (request.IsRetrieveChildrenIdentifiers()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, childLevel.publicId AS childPublicId " - "FROM Resources as currentLevel " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId " - " INNER JOIN Resources childLevel ON childLevel.parentId = currentLevel.internalId"); - formatter.Bind(statement); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddChildIdentifier(GetChildResourceType(request.GetLevel()), statement.ColumnString(1)); - } - } - - if (request.IsRetrieveParentIdentifier()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, parentLevel.publicId AS parentPublicId " - "FROM Resources as currentLevel " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId " - " INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - const std::string& parentId = statement.ColumnString(1); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).SetParentIdentifier(parentId); - } - } - - if (request.IsRetrieveMetadata()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, metadata.type, metadata.value " - "FROM Metadata " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Metadata.id"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddMetadata(static_cast<MetadataType>(statement.ColumnInt(1)), - statement.ColumnString(2)); - } - } - - if (request.IsRetrieveLabels()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, label " - "FROM Labels " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Labels.id"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddLabel(statement.ColumnString(1)); - } - } - - if (request.IsRetrieveAttachments()) - { - SQLite::Statement statement(db_, SQLITE_FROM_HERE, - "SELECT filtered.publicId, uuid, fileType, uncompressedSize, compressionType, compressedSize, " - " uncompressedMD5, compressedMD5 " - "FROM AttachedFiles " - " INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = AttachedFiles.id"); - - while (statement.Step()) - { - const std::string& resourceId = statement.ColumnString(0); - FileInfo attachment = FileInfo(statement.ColumnString(1), - static_cast<FileContentType>(statement.ColumnInt(2)), - statement.ColumnInt64(3), - statement.ColumnString(6), - static_cast<CompressionType>(statement.ColumnInt(4)), - statement.ColumnInt64(5), - statement.ColumnString(7)); - - assert(response.HasResource(resourceId)); - response.GetResource(resourceId).AddAttachment(attachment); - }; - } - - // TODO-FIND: implement other responseContent: ResponseContent_ChildInstanceId, ResponseContent_ChildrenMetadata (later: ResponseContent_IsStable) - - } - -#endif - } -#endif -
--- a/OrthancServer/Resources/Graveyard/SetupAnonymization2011.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,258 +0,0 @@ - /** - * This is a manual implementation by Alain Mazy. Only kept for reference. - * https://bitbucket.org/sjodogne/orthanc/commits/c6defdc4c611fca2ab528ba2c6937a742e0329a8?at=issue-46-anonymization - **/ - - void DicomModification::SetupAnonymization2011() - { - // This is Table E.1-1 from PS 3.15-2011 - DICOM Part 15: Security and System Management Profiles - // https://raw.githubusercontent.com/jodogne/dicom-specification/master/2011/11_15pu.pdf - - removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID - removals_.insert(DicomTag(0x0000, 0x1001)); // Requested SOP Instance UID - removals_.insert(DicomTag(0x0002, 0x0003)); // Media Storage SOP Instance UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances - removals_.insert(DicomTag(0x0004, 0x1511)); // Referenced SOP Instance UID in File - removals_.insert(DicomTag(0x0008, 0x0010)); // Irradiation Event UID - removals_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID - //removals_.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID => set in Apply() - clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date - clearings_.insert(DicomTag(0x0008, 0x0021)); // Series Date - clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time - clearings_.insert(DicomTag(0x0008, 0x0031)); // Series Time - removals_.insert(DicomTag(0x0008, 0x0022)); // Acquisition Date - removals_.insert(DicomTag(0x0008, 0x0023)); // Content Date - removals_.insert(DicomTag(0x0008, 0x0024)); // Overlay Date - removals_.insert(DicomTag(0x0008, 0x0025)); // Curve Date - removals_.insert(DicomTag(0x0008, 0x002a)); // Acquisition DateTime - removals_.insert(DicomTag(0x0008, 0x0032)); // Acquisition Time - removals_.insert(DicomTag(0x0008, 0x0033)); // Content Time - removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time - removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time - removals_.insert(DicomTag(0x0008, 0x0050)); // Accession Number - removals_.insert(DicomTag(0x0008, 0x0058)); // Failed SOP Instance UID List - removals_.insert(DicomTag(0x0008, 0x0080)); // Institution Name - removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address - removals_.insert(DicomTag(0x0008, 0x0082)); // Institution Code Sequence - removals_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name - 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's Identification Sequence - removals_.insert(DicomTag(0x0008, 0x010d)); // Context Group Extension Creator UID - removals_.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC - removals_.insert(DicomTag(0x0008, 0x0300)); // Current Patient Location - removals_.insert(DicomTag(0x0008, 0x1010)); // 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, 0x1048)); // Physician(s) of Record - removals_.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of Record Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name - removals_.insert(DicomTag(0x0008, 0x1052)); // Performing Physicians Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study - removals_.insert(DicomTag(0x0008, 0x1062)); // Physician Reading Study Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1070)); // Operators' Name - removals_.insert(DicomTag(0x0008, 0x1072)); // Operators' Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description - removals_.insert(DicomTag(0x0008, 0x1084)); // Admitting Diagnoses Code Sequence - removals_.insert(DicomTag(0x0008, 0x1110)); // Referenced Study Sequence - removals_.insert(DicomTag(0x0008, 0x1111)); // Referenced Performed Procedure Step Sequence - removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence - removals_.insert(DicomTag(0x0008, 0x1140)); // Referenced Image Sequence - removals_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID - removals_.insert(DicomTag(0x0008, 0x1195)); // Transaction UID - removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description - removals_.insert(DicomTag(0x0008, 0x2112)); // Source Image Sequence - removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments - removals_.insert(DicomTag(0x0008, 0x9123)); // Creator Version UID - //removals_.insert(DicomTag(0x0010, 0x0010)); // Patient's Name => cf. below (*) - //removals_.insert(DicomTag(0x0010, 0x0020)); // Patient ID => cf. below (*) - removals_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date - removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time - clearings_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex - 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, 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)); // PatientTelephoneNumbers - 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's 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)); // 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(0x0018, 0x0010)); // Contrast Bolus Agent - removals_.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number - removals_.insert(DicomTag(0x0018, 0x1002)); // Device UID - 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, 0x1030)); // Protocol Name - removals_.insert(DicomTag(0x0018, 0x1400)); // Acquisition Device Processing Description - removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments - removals_.insert(DicomTag(0x0018, 0x700a)); // Detector ID - removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description - removals_.insert(DicomTag(0x0018, 0x9424)); // Acquisition Protocol Description - //removals_.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => set in Apply() - //removals_.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => set in Apply() - removals_.insert(DicomTag(0x0020, 0x0010)); // Study ID - removals_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID - removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID - removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID - removals_.insert(DicomTag(0x0020, 0x3404)); // Modifying Device Manufacturer - 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(0x0020, 0x9161)); // Concatenation UID - removals_.insert(DicomTag(0x0020, 0x9164)); // Dimension Organization UID - //removals_.insert(DicomTag(0x0028, 0x1199)); // Palette Color Lookup Table UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances - //removals_.insert(DicomTag(0x0028, 0x1214)); // Large Palette Color Lookup Table UID => TODO: replace with a non-zero length UID that is internally consistent within a set of Instances - removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments - removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer - removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location - 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, 0x1060)); // Requesting Procedure Description - removals_.insert(DicomTag(0x0032, 0x1070)); // Requested Contrast Agent - removals_.insert(DicomTag(0x0032, 0x4000)); // Study Comments - removals_.insert(DicomTag(0x0038, 0x0010)); // Admission ID - removals_.insert(DicomTag(0x0038, 0x0011)); // Issuer of Admission ID - 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, 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, 0x0400)); // Patient's Institution Residence - removals_.insert(DicomTag(0x0038, 0x0500)); // Patient State - removals_.insert(DicomTag(0x0038, 0x4000)); // Visit Comments - removals_.insert(DicomTag(0x0038, 0x1234)); // Referenced Patient Alias Sequence - 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 Name - removals_.insert(DicomTag(0x0040, 0x0007)); // Scheduled Procedure Step Description - 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, 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, 0x0248)); // Performed Station Name Code Sequence - 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 Performed Procedure Step - removals_.insert(DicomTag(0x0040, 0x0555)); // Acquisition Context Sequence - removals_.insert(DicomTag(0x0040, 0x1001)); // Requested Procedure ID - removals_.insert(DicomTag(0x0040, 0x1010)); // Names of Intended Recipient of Results - removals_.insert(DicomTag(0x0040, 0x1011)); // Intended Recipient of Results Identification Sequence - removals_.insert(DicomTag(0x0040, 0x1004)); // Patient Transport Arrangements - removals_.insert(DicomTag(0x0040, 0x1005)); // Requested Procedure Location - removals_.insert(DicomTag(0x0040, 0x1101)); // Person Identification Code Sequence - removals_.insert(DicomTag(0x0040, 0x1102)); // Person Address - removals_.insert(DicomTag(0x0040, 0x1103)); // Person Telephone Numbers - removals_.insert(DicomTag(0x0040, 0x1400)); // Requested Procedure Comments - removals_.insert(DicomTag(0x0040, 0x2001)); // Reason for Imaging Service Request - removals_.insert(DicomTag(0x0040, 0x2008)); // Order Entered By - removals_.insert(DicomTag(0x0040, 0x2009)); // Order Enterer Location - removals_.insert(DicomTag(0x0040, 0x2010)); // Order Callback Phone Number - removals_.insert(DicomTag(0x0040, 0x2016)); // Placer Order Number of Imaging Service Request - removals_.insert(DicomTag(0x0040, 0x2017)); // Filler Order Number of Imaging Service Request - removals_.insert(DicomTag(0x0040, 0x2400)); // Imaging Service Request Comments - removals_.insert(DicomTag(0x0040, 0x4023)); // Referenced General Purpose Scheduled Procedure Step Transaction UID - 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, 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 Performers Organization - removals_.insert(DicomTag(0x0040, 0x4037)); // Human Performers Name - removals_.insert(DicomTag(0x0040, 0xa027)); // Verifying Organization - removals_.insert(DicomTag(0x0040, 0xa073)); // Verifying Observer Sequence - removals_.insert(DicomTag(0x0040, 0xa075)); // Verifying Observer Name - 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, 0xa088)); // Verifying Observer Identification Code Sequence - removals_.insert(DicomTag(0x0040, 0xa123)); // Person Name - removals_.insert(DicomTag(0x0040, 0xa124)); // UID - removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence - removals_.insert(DicomTag(0x0040, 0x3001)); // Confidentiality Constraint on Patient Data Description - removals_.insert(DicomTag(0x0040, 0xdb0c)); // Template Extension Organization UID - removals_.insert(DicomTag(0x0040, 0xdb0d)); // Template Extension Creator UID - removals_.insert(DicomTag(0x0070, 0x0001)); // Graphic Annotation Sequence - removals_.insert(DicomTag(0x0070, 0x0084)); // Content Creator's Name - removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence - removals_.insert(DicomTag(0x0070, 0x031a)); // Fiducial UID - removals_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID - 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 Key Words - removals_.insert(DicomTag(0x0400, 0x0100)); // Digital Signature UID - 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, 0x0561)); // Original Attributes Sequence - removals_.insert(DicomTag(0x2030, 0x0020)); // Text String - removals_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID - removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID - removals_.insert(DicomTag(0x300a, 0x0013)); // Dose Reference UID - removals_.insert(DicomTag(0x300e, 0x0008)); // Reviewer Name - removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary - removals_.insert(DicomTag(0x4000, 0x4000)); // Text Comments - removals_.insert(DicomTag(0x4008, 0x0042)); // Results ID Issuer - removals_.insert(DicomTag(0x4008, 0x0102)); // Interpretation Recorder - 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, 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, 0x0202)); // Interpretation ID Issuer - removals_.insert(DicomTag(0x4008, 0x0300)); // Impressions - removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments - removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signature Sequence - removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding - //removals_.insert(DicomTag(0x60xx, 0x4000)); // Overlay Comments => TODO - //removals_.insert(DicomTag(0x60xx, 0x3000)); // Overlay Data => TODO - - // Set the DeidentificationMethod tag - ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2011); - }
--- a/OrthancServer/Resources/ImplementationNotes/DatabasesClassHierarchy.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/ImplementationNotes/DatabasesClassHierarchy.txt Thu Jan 30 17:41:33 2025 +0100 @@ -21,7 +21,7 @@ - define it in OrthancPluginDatabaseV4 - define a NotImplemented default implementation in BaseDatabaseWrapper - optionally define it in SQLiteDatabaseWrapper if it can be implemented in SQLite -- very likely define it as a DbCapabilities in IDatabaseWrapper::DbCapabilities (e.g: Has/SetUpdateAndGetStatistics()) such that the Orthanc +- very likely define it as a DbCapabilities in IDatabaseWrapper::DbCapabilities (e.g: Has/SetHasUpdateAndGetStatistics()) such that the Orthanc core knows if it can use it or not. Then, in the orthanc-databases repo, you should:
--- a/OrthancServer/Resources/PreventProtobufDirectoryLeaks.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/PreventProtobufDirectoryLeaks.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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 @@ -29,13 +29,21 @@ with open(sys.argv[1], 'r') as f: s = f.read() -s = s.replace('__FILE__', '__ORTHANC_FILE__') +if False: + # This was the version in Orthanc 1.12.4, doesn't seem to work anymore + s = s.replace('__FILE__', '__ORTHANC_FILE__') -s = """ + s = """ #if !defined(__ORTHANC_FILE__) # define __ORTHANC_FILE__ __FILE__ #endif """ + s +else: + # New version in Orthanc 1.12.5 + s = """ +#undef __FILE__ +#define __FILE__ __ORTHANC_FILE__ +""" + s with open(sys.argv[1], 'w') as f: f.write(s)
--- a/OrthancServer/Resources/RunCppCheck.sh Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/RunCppCheck.sh Thu Jan 30 17:41:33 2025 +0100 @@ -12,12 +12,12 @@ constParameter:../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp knownArgument:../../OrthancFramework/UnitTestsSources/ImageTests.cpp knownConditionTrueFalse:../../OrthancServer/Plugins/Engine/OrthancPlugins.cpp -nullPointer:../../OrthancFramework/UnitTestsSources/RestApiTests.cpp:316 -stlFindInsert:../../OrthancFramework/Sources/DicomFormat/DicomMap.cpp:1477 +nullPointer:../../OrthancFramework/UnitTestsSources/RestApiTests.cpp:321 +stlFindInsert:../../OrthancFramework/Sources/DicomFormat/DicomMap.cpp:1525 stlFindInsert:../../OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp:166 stlFindInsert:../../OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp:74 stlFindInsert:../../OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp:65 -stlFindInsert:../../OrthancServer/Sources/OrthancWebDav.cpp:480 +stlFindInsert:../../OrthancServer/Sources/OrthancWebDav.cpp:328 stlFindInsert:../../OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp:41 stlFindInsert:../../OrthancServer/Sources/ServerJobs/SplitStudyJob.cpp:191 stlFindInsert:../../OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp:361 @@ -27,7 +27,7 @@ syntaxError:../../OrthancServer/UnitTestsSources/UnitTestsMain.cpp:322 uninitMemberVar:../../OrthancServer/Sources/ServerJobs/StorageCommitmentScpJob.cpp:417 unreadVariable:../../OrthancFramework/Sources/FileStorage/StorageAccessor.cpp -unreadVariable:../../OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp:1123 +unreadVariable:../../OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp:1173 unusedFunction useInitializationList:../../OrthancFramework/Sources/Images/PngReader.cpp:91 useInitializationList:../../OrthancFramework/Sources/Images/PngWriter.cpp:99 @@ -36,7 +36,7 @@ assertWithSideEffect:../../OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp:1026 assertWithSideEffect:../../OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp:292 assertWithSideEffect:../../OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp:391 -assertWithSideEffect:../../OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp:3527 +assertWithSideEffect:../../OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp:3058 assertWithSideEffect:../../OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp:286 assertWithSideEffect:../../OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.cpp:454 EOF
--- a/OrthancServer/Resources/Samples/CppHelpers/Logging/ILogger.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/CppHelpers/Logging/ILogger.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/CppHelpers/Logging/NullLogger.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/CppHelpers/Logging/NullLogger.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancLogger.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancLogger.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancLogger.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancLogger.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancPluginLogger.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancPluginLogger.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancPluginLogger.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/CppHelpers/Logging/OrthancPluginLogger.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/ImportDicomFiles/ImportDicomFiles.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/ImportDicomFiles/ImportDicomFiles.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/ImportDicomFiles/OrthancImport.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/ImportDicomFiles/OrthancImport.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Lua/CallWebService.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Lua/CallWebService.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/AnonymizeAllPatients.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/AnonymizeAllPatients.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/ArchiveAllPatients.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/ArchiveAllPatients.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/ArchiveStudiesInTimeRange.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/ArchiveStudiesInTimeRange.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/AutoClassify.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/AutoClassify.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/ChangesLoop.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/ChangesLoop.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/ContinuousPatientAnonymization.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/ContinuousPatientAnonymization.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/DeleteAllStudies.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/DeleteAllStudies.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/DicomizeImage.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/DicomizeImage.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/DownloadAnonymized.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/DownloadAnonymized.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/HighPerformanceAutoRouting.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/HighPerformanceAutoRouting.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/ManualModification.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/ManualModification.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/MicroCTDicomization.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/MicroCTDicomization.py Thu Jan 30 17:41:33 2025 +0100 @@ -5,8 +5,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/Replicate.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/Replicate.py Thu Jan 30 17:41:33 2025 +0100 @@ -4,8 +4,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Python/RestToolbox.py Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Python/RestToolbox.py Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Tools/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Tools/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/Tools/RecoverCompressedFile.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/Tools/RecoverCompressedFile.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/WebApplications/DrawingDicomizer.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/WebApplications/DrawingDicomizer.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/WebApplications/DrawingDicomizer/orthanc.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/WebApplications/DrawingDicomizer/orthanc.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Samples/WebApplications/NodeToolbox.js Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Samples/WebApplications/NodeToolbox.js Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Resources/Testing/Issue32/Cpp/CMakeLists.txt Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Resources/Testing/Issue32/Cpp/CMakeLists.txt Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ # 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 +# Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2025 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Database/BaseCompatibilityTransaction.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,88 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "BaseCompatibilityTransaction.h" + +#include "../../../OrthancFramework/Sources/OrthancException.h" +#include "Compatibility/GenericFind.h" + +namespace Orthanc +{ + int64_t BaseCompatibilityTransaction::IncrementGlobalProperty(GlobalProperty property, + int64_t increment, + bool shared) + { + throw OrthancException(ErrorCode_NotImplemented); // Not supported + } + + void BaseCompatibilityTransaction::UpdateAndGetStatistics(int64_t& patientsCount, + int64_t& studiesCount, + int64_t& seriesCount, + int64_t& instancesCount, + int64_t& compressedSize, + int64_t& uncompressedSize) + { + throw OrthancException(ErrorCode_NotImplemented); // Not supported + } + + void BaseCompatibilityTransaction::GetChangesExtended(std::list<ServerIndexChange>& target /*out*/, + bool& done /*out*/, + int64_t since, + int64_t to, + uint32_t limit, + const std::set<ChangeType>& filterType) + { + throw OrthancException(ErrorCode_NotImplemented); // Not supported + } + + void BaseCompatibilityTransaction::ExecuteCount(uint64_t& count, + const FindRequest& request, + const IDatabaseWrapper::Capabilities& capabilities) + { + throw OrthancException(ErrorCode_NotImplemented); // Not supported + } + + void BaseCompatibilityTransaction::ExecuteFind(FindResponse& response, + const FindRequest& request, + const IDatabaseWrapper::Capabilities& capabilities) + { + throw OrthancException(ErrorCode_NotImplemented); // Not supported + } + + void BaseCompatibilityTransaction::ExecuteFind(std::list<std::string>& identifiers, + const IDatabaseWrapper::Capabilities& capabilities, + const FindRequest& request) + { + Compatibility::GenericFind find(*this, *this); + find.ExecuteFind(identifiers, capabilities, request); + } + + void BaseCompatibilityTransaction::ExecuteExpand(FindResponse& response, + const IDatabaseWrapper::Capabilities& capabilities, + const FindRequest& request, + const std::string& identifier) + { + Compatibility::GenericFind find(*this, *this); + find.ExecuteExpand(response, capabilities, request, identifier); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Database/BaseCompatibilityTransaction.h Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,76 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IDatabaseWrapper.h" + +namespace Orthanc +{ + /** + * This class provides a default "not implemented" implementation + * for all recent methods (1.12.X) + **/ + + class BaseCompatibilityTransaction : + public IDatabaseWrapper::ITransaction, + public IDatabaseWrapper::ICompatibilityTransaction + { + public: + virtual int64_t IncrementGlobalProperty(GlobalProperty property, + int64_t increment, + bool shared) ORTHANC_OVERRIDE; + + virtual void UpdateAndGetStatistics(int64_t& patientsCount, + int64_t& studiesCount, + int64_t& seriesCount, + int64_t& instancesCount, + int64_t& compressedSize, + int64_t& uncompressedSize) ORTHANC_OVERRIDE; + + virtual void ExecuteCount(uint64_t& count, + const FindRequest& request, + const IDatabaseWrapper::Capabilities& capabilities) ORTHANC_OVERRIDE; + + virtual void ExecuteFind(FindResponse& response, + const FindRequest& request, + const IDatabaseWrapper::Capabilities& capabilities) ORTHANC_OVERRIDE; + + virtual void ExecuteFind(std::list<std::string>& identifiers, + const IDatabaseWrapper::Capabilities& capabilities, + const FindRequest& request) ORTHANC_OVERRIDE; + + virtual void ExecuteExpand(FindResponse& response, + const IDatabaseWrapper::Capabilities& capabilities, + const FindRequest& request, + const std::string& identifier) ORTHANC_OVERRIDE; + + virtual void GetChangesExtended(std::list<ServerIndexChange>& target /*out*/, + bool& done /*out*/, + int64_t since, + int64_t to, + uint32_t limit, + const std::set<ChangeType>& filterType) ORTHANC_OVERRIDE; + }; + +}
--- a/OrthancServer/Sources/Database/BaseDatabaseWrapper.cpp Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "BaseDatabaseWrapper.h" - -#include "../../../OrthancFramework/Sources/OrthancException.h" -#include "Compatibility/GenericFind.h" - -namespace Orthanc -{ - int64_t BaseDatabaseWrapper::BaseTransaction::IncrementGlobalProperty(GlobalProperty property, - int64_t increment, - bool shared) - { - throw OrthancException(ErrorCode_NotImplemented); // Not supported - } - - - void BaseDatabaseWrapper::BaseTransaction::UpdateAndGetStatistics(int64_t& patientsCount, - int64_t& studiesCount, - int64_t& seriesCount, - int64_t& instancesCount, - int64_t& compressedSize, - int64_t& uncompressedSize) - { - throw OrthancException(ErrorCode_NotImplemented); // Not supported - } - - void BaseDatabaseWrapper::BaseTransaction::GetChangesExtended(std::list<ServerIndexChange>& target /*out*/, - bool& done /*out*/, - int64_t since, - int64_t to, - uint32_t limit, - const std::set<ChangeType>& filterType) - { - throw OrthancException(ErrorCode_NotImplemented); // Not supported - } - - - - void BaseDatabaseWrapper::BaseTransaction::ExecuteFind(FindResponse& response, - const FindRequest& request, - const Capabilities& capabilities) - { - throw OrthancException(ErrorCode_NotImplemented); // Not supported - } - - - void BaseDatabaseWrapper::BaseTransaction::ExecuteFind(std::list<std::string>& identifiers, - const Capabilities& capabilities, - const FindRequest& request) - { - Compatibility::GenericFind find(*this); - find.ExecuteFind(identifiers, capabilities, request); - } - - - void BaseDatabaseWrapper::BaseTransaction::ExecuteExpand(FindResponse& response, - const Capabilities& capabilities, - const FindRequest& request, - const std::string& identifier) - { - Compatibility::GenericFind find(*this); - find.ExecuteExpand(response, capabilities, request, identifier); - } - - - uint64_t BaseDatabaseWrapper::MeasureLatency() - { - throw OrthancException(ErrorCode_NotImplemented); // only implemented in V4 - } -}
--- a/OrthancServer/Sources/Database/BaseDatabaseWrapper.h Wed Oct 09 11:06:20 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/** - * 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 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "IDatabaseWrapper.h" - -namespace Orthanc -{ - /** - * This class provides a default "not implemented" implementation - * for all recent methods (1.12.X) - **/ - class BaseDatabaseWrapper : public IDatabaseWrapper - { - public: - class BaseTransaction : public IDatabaseWrapper::ITransaction - { - public: - virtual int64_t IncrementGlobalProperty(GlobalProperty property, - int64_t increment, - bool shared) ORTHANC_OVERRIDE; - - virtual void UpdateAndGetStatistics(int64_t& patientsCount, - int64_t& studiesCount, - int64_t& seriesCount, - int64_t& instancesCount, - int64_t& compressedSize, - int64_t& uncompressedSize) ORTHANC_OVERRIDE; - - virtual void ExecuteFind(FindResponse& response, - const FindRequest& request, - const Capabilities& capabilities) ORTHANC_OVERRIDE; - - virtual void ExecuteFind(std::list<std::string>& identifiers, - const Capabilities& capabilities, - const FindRequest& request) ORTHANC_OVERRIDE; - - virtual void ExecuteExpand(FindResponse& response, - const Capabilities& capabilities, - const FindRequest& request, - const std::string& identifier) ORTHANC_OVERRIDE; - - virtual void GetChangesExtended(std::list<ServerIndexChange>& target /*out*/, - bool& done /*out*/, - int64_t since, - int64_t to, - uint32_t limit, - const std::set<ChangeType>& filterType) ORTHANC_OVERRIDE; - }; - - virtual uint64_t MeasureLatency() ORTHANC_OVERRIDE; - - virtual bool HasIntegratedFind() const ORTHANC_OVERRIDE - { - return false; - } - }; -}
--- a/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -33,14 +33,6 @@ { namespace Compatibility { - static bool IsRequestWithoutContraint(const FindRequest& request) - { - return (request.GetDicomTagConstraints().IsEmpty() && - request.GetMetadataConstraintsCount() == 0 && - request.GetLabels().empty() && - request.GetOrdering().empty()); - } - static void GetChildren(std::list<int64_t>& target, IDatabaseWrapper::ITransaction& transaction, const std::list<int64_t>& resources) @@ -56,7 +48,7 @@ } static void GetChildren(std::list<std::string>& target, - IDatabaseWrapper::ITransaction& transaction, + IDatabaseWrapper::ICompatibilityTransaction& transaction, const std::list<int64_t>& resources) { target.clear(); @@ -71,6 +63,7 @@ static void GetChildrenIdentifiers(std::list<std::string>& children, IDatabaseWrapper::ITransaction& transaction, + IDatabaseWrapper::ICompatibilityTransaction& compatibilityTransaction, const OrthancIdentifiers& identifiers, ResourceType topLevel, ResourceType bottomLevel) @@ -100,7 +93,7 @@ ResourceType nextLevel = GetChildResourceType(currentLevel); if (nextLevel == bottomLevel) { - GetChildren(children, transaction, currentResources); + GetChildren(children, compatibilityTransaction, currentResources); } else { @@ -123,7 +116,12 @@ throw OrthancException(ErrorCode_NotImplemented, "The database backend doesn't support labels"); } - if (IsRequestWithoutContraint(request) && + if (!request.GetOrdering().empty()) + { + throw OrthancException(ErrorCode_NotImplemented, "The database backend doesn't support ordering"); + } + + if (!request.HasConstraints() && !request.GetOrthancIdentifiers().HasPatientId() && !request.GetOrthancIdentifiers().HasStudyId() && !request.GetOrthancIdentifiers().HasSeriesId() && @@ -135,7 +133,7 @@ } else if (request.GetLimitsCount() != 0) { - transaction_.GetAllPublicIds(identifiers, request.GetLevel(), request.GetLimitsSince(), request.GetLimitsCount()); + compatibilityTransaction_.GetAllPublicIdsCompatibility(identifiers, request.GetLevel(), request.GetLimitsSince(), request.GetLimitsCount()); } else { @@ -155,47 +153,7 @@ } } } - else if (IsRequestWithoutContraint(request) && - request.GetLevel() == ResourceType_Patient && - request.GetOrthancIdentifiers().HasPatientId() && - !request.GetOrthancIdentifiers().HasStudyId() && - !request.GetOrthancIdentifiers().HasSeriesId() && - !request.GetOrthancIdentifiers().HasInstanceId()) - { - // TODO-FIND: This is a trivial case for which no transaction is needed - identifiers.push_back(request.GetOrthancIdentifiers().GetPatientId()); - } - else if (IsRequestWithoutContraint(request) && - request.GetLevel() == ResourceType_Study && - !request.GetOrthancIdentifiers().HasPatientId() && - request.GetOrthancIdentifiers().HasStudyId() && - !request.GetOrthancIdentifiers().HasSeriesId() && - !request.GetOrthancIdentifiers().HasInstanceId()) - { - // TODO-FIND: This is a trivial case for which no transaction is needed - identifiers.push_back(request.GetOrthancIdentifiers().GetStudyId()); - } - else if (IsRequestWithoutContraint(request) && - request.GetLevel() == ResourceType_Series && - !request.GetOrthancIdentifiers().HasPatientId() && - !request.GetOrthancIdentifiers().HasStudyId() && - request.GetOrthancIdentifiers().HasSeriesId() && - !request.GetOrthancIdentifiers().HasInstanceId()) - { - // TODO-FIND: This is a trivial case for which no transaction is needed - identifiers.push_back(request.GetOrthancIdentifiers().GetSeriesId()); - } - else if (IsRequestWithoutContraint(request) && - request.GetLevel() == ResourceType_Instance && - !request.GetOrthancIdentifiers().HasPatientId() && - !request.GetOrthancIdentifiers().HasStudyId() && - !request.GetOrthancIdentifiers().HasSeriesId() && - request.GetOrthancIdentifiers().HasInstanceId()) - { - // TODO-FIND: This is a trivial case for which no transaction is needed - identifiers.push_back(request.GetOrthancIdentifiers().GetInstanceId()); - } - else if (IsRequestWithoutContraint(request) && + else if (!request.HasConstraints() && (request.GetLevel() == ResourceType_Study || request.GetLevel() == ResourceType_Series || request.GetLevel() == ResourceType_Instance) && @@ -204,9 +162,10 @@ !request.GetOrthancIdentifiers().HasSeriesId() && !request.GetOrthancIdentifiers().HasInstanceId()) { - GetChildrenIdentifiers(identifiers, transaction_, request.GetOrthancIdentifiers(), ResourceType_Patient, request.GetLevel()); + GetChildrenIdentifiers(identifiers, transaction_, compatibilityTransaction_, + request.GetOrthancIdentifiers(), ResourceType_Patient, request.GetLevel()); } - else if (IsRequestWithoutContraint(request) && + else if (!request.HasConstraints() && (request.GetLevel() == ResourceType_Series || request.GetLevel() == ResourceType_Instance) && !request.GetOrthancIdentifiers().HasPatientId() && @@ -214,16 +173,18 @@ !request.GetOrthancIdentifiers().HasSeriesId() && !request.GetOrthancIdentifiers().HasInstanceId()) { - GetChildrenIdentifiers(identifiers, transaction_, request.GetOrthancIdentifiers(), ResourceType_Study, request.GetLevel()); + GetChildrenIdentifiers(identifiers, transaction_, compatibilityTransaction_, + request.GetOrthancIdentifiers(), ResourceType_Study, request.GetLevel()); } - else if (IsRequestWithoutContraint(request) && + else if (!request.HasConstraints() && request.GetLevel() == ResourceType_Instance && !request.GetOrthancIdentifiers().HasPatientId() && !request.GetOrthancIdentifiers().HasStudyId() && request.GetOrthancIdentifiers().HasSeriesId() && !request.GetOrthancIdentifiers().HasInstanceId()) { - GetChildrenIdentifiers(identifiers, transaction_, request.GetOrthancIdentifiers(), ResourceType_Series, request.GetLevel()); + GetChildrenIdentifiers(identifiers, transaction_, compatibilityTransaction_, + request.GetOrthancIdentifiers(), ResourceType_Series, request.GetLevel()); } else if (request.GetMetadataConstraintsCount() == 0 && request.GetOrdering().empty() && @@ -232,9 +193,9 @@ !request.GetOrthancIdentifiers().HasSeriesId() && !request.GetOrthancIdentifiers().HasInstanceId()) { - transaction_.ApplyLookupResources(identifiers, NULL /* TODO-FIND: Could the "instancesId" information be exploited? */, - request.GetDicomTagConstraints(), request.GetLevel(), request.GetLabels(), - request.GetLabelsConstraint(), request.HasLimits() ? request.GetLimitsCount() : 0); + compatibilityTransaction_.ApplyLookupResources(identifiers, NULL /* TODO-FIND: Could the "instancesId" information be exploited? */, + request.GetDicomTagConstraints(), request.GetLevel(), request.GetLabels(), + request.GetLabelsConstraint(), request.HasLimits() ? request.GetLimitsCount() : 0); } else { @@ -388,7 +349,7 @@ if (request.IsRetrieveParentIdentifier()) { - if (!transaction_.LookupResourceAndParent(internalId, level, parent, identifier)) + if (!compatibilityTransaction_.LookupResourceAndParent(internalId, level, parent, identifier)) { return; // The resource is not available anymore } @@ -436,7 +397,32 @@ if (request.IsRetrieveMetadata()) { - transaction_.GetAllMetadata(resource->GetMetadata(level), internalId); + std::map<MetadataType, std::string> metadata; + transaction_.GetAllMetadata(metadata, internalId); + + for (std::map<MetadataType, std::string>::const_iterator + it = metadata.begin(); it != metadata.end(); ++it) + { + if (request.IsRetrieveMetadataRevisions() && + capabilities.HasRevisionsSupport()) + { + std::string value; + int64_t revision; + if (transaction_.LookupMetadata(value, revision, internalId, it->first) && + value == it->second) + { + resource->AddMetadata(level, it->first, it->second, revision); + } + else + { + throw OrthancException(ErrorCode_DatabasePlugin); + } + } + else + { + resource->AddMetadata(level, it->first, it->second, 0 /* revision not requested */); + } + } } { @@ -465,7 +451,14 @@ if (request.GetParentSpecification(currentLevel).IsRetrieveMetadata()) { - transaction_.GetAllMetadata(resource->GetMetadata(currentLevel), currentId); + std::map<MetadataType, std::string> metadata; + transaction_.GetAllMetadata(metadata, currentId); + + for (std::map<MetadataType, std::string>::const_iterator + it = metadata.begin(); it != metadata.end(); ++it) + { + resource->AddMetadata(currentLevel, it->first, it->second, 0 /* revision not request */); + } } } } @@ -473,7 +466,7 @@ if (capabilities.HasLabelsSupport() && request.IsRetrieveLabels()) { - transaction_.ListLabels(resource->GetLabels(), internalId); + compatibilityTransaction_.ListLabels(resource->GetLabels(), internalId); } if (request.IsRetrieveAttachments()) @@ -488,7 +481,7 @@ if (transaction_.LookupAttachment(info, revision, internalId, *it) && info.GetContentType() == *it) { - resource->AddAttachment(info); + resource->AddAttachment(info, revision); } else { @@ -509,17 +502,19 @@ { ResourceType childrenLevel = GetChildResourceType(currentLevel); - if (request.GetChildrenSpecification(childrenLevel).IsRetrieveIdentifiers()) + if (request.GetChildrenSpecification(childrenLevel).IsRetrieveIdentifiers() || + request.GetChildrenSpecification(childrenLevel).IsRetrieveCount()) { for (std::list<int64_t>::const_iterator it = currentIds.begin(); it != currentIds.end(); ++it) { std::list<std::string> ids; - transaction_.GetChildrenPublicId(ids, *it); + compatibilityTransaction_.GetChildrenPublicId(ids, *it); for (std::list<std::string>::const_iterator it2 = ids.begin(); it2 != ids.end(); ++it2) { resource->AddChildIdentifier(childrenLevel, *it2); } + resource->IncrementChildrenCount(childrenLevel, ids.size()); } }
--- a/OrthancServer/Sources/Database/Compatibility/GenericFind.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/GenericFind.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -33,14 +33,17 @@ { private: IDatabaseWrapper::ITransaction& transaction_; + IDatabaseWrapper::ICompatibilityTransaction& compatibilityTransaction_; void RetrieveMainDicomTags(FindResponse::Resource& target, ResourceType level, int64_t internalId); public: - explicit GenericFind(IDatabaseWrapper::ITransaction& transaction) : - transaction_(transaction) + explicit GenericFind(IDatabaseWrapper::ITransaction& transaction, + IDatabaseWrapper::ICompatibilityTransaction& compatibilityTransaction) : + transaction_(transaction), + compatibilityTransaction_(compatibilityTransaction) { }
--- a/OrthancServer/Sources/Database/Compatibility/ICreateInstance.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ICreateInstance.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/ICreateInstance.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ICreateInstance.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/IGetChildrenMetadata.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/IGetChildrenMetadata.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/IGetChildrenMetadata.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/IGetChildrenMetadata.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResourceAndParent.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ILookupResourceAndParent.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResourceAndParent.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ILookupResourceAndParent.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResources.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ILookupResources.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResources.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ILookupResources.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/ISetResourcesContent.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ISetResourcesContent.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/SetOfResources.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/SetOfResources.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Compatibility/SetOfResources.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/SetOfResources.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/FindRequest.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/FindRequest.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -90,6 +90,7 @@ labelsConstraint_(LabelsConstraint_All), retrieveMainDicomTags_(false), retrieveMetadata_(false), + retrieveMetadataRevisions_(false), retrieveLabels_(false), retrieveAttachments_(false), retrieveParentIdentifier_(false), @@ -225,16 +226,18 @@ void FindRequest::AddOrdering(const DicomTag& tag, + OrderingCast cast, OrderingDirection direction) { - ordering_.push_back(new Ordering(Key(tag), direction)); + ordering_.push_back(new Ordering(Key(tag), cast, direction)); } void FindRequest::AddOrdering(MetadataType metadataType, + OrderingCast cast, OrderingDirection direction) { - ordering_.push_back(new Ordering(Key(metadataType), direction)); + ordering_.push_back(new Ordering(Key(metadataType), cast, direction)); } @@ -281,4 +284,61 @@ return retrieveOneInstanceMetadataAndAttachments_; } } + + bool FindRequest::HasConstraints() const + { + return (!GetDicomTagConstraints().IsEmpty() || + GetMetadataConstraintsCount() != 0 || + !GetLabels().empty() || + !GetOrdering().empty()); + } + + + bool FindRequest::IsTrivialFind(std::string& publicId /* out */) const + { + if (HasConstraints()) + { + return false; + } + else if (GetLevel() == ResourceType_Patient && + GetOrthancIdentifiers().HasPatientId() && + !GetOrthancIdentifiers().HasStudyId() && + !GetOrthancIdentifiers().HasSeriesId() && + !GetOrthancIdentifiers().HasInstanceId()) + { + publicId = GetOrthancIdentifiers().GetPatientId(); + return true; + } + else if (GetLevel() == ResourceType_Study && + !GetOrthancIdentifiers().HasPatientId() && + GetOrthancIdentifiers().HasStudyId() && + !GetOrthancIdentifiers().HasSeriesId() && + !GetOrthancIdentifiers().HasInstanceId()) + { + publicId = GetOrthancIdentifiers().GetStudyId(); + return true; + } + else if (GetLevel() == ResourceType_Series && + !GetOrthancIdentifiers().HasPatientId() && + !GetOrthancIdentifiers().HasStudyId() && + GetOrthancIdentifiers().HasSeriesId() && + !GetOrthancIdentifiers().HasInstanceId()) + { + publicId = GetOrthancIdentifiers().GetSeriesId(); + return true; + } + else if (GetLevel() == ResourceType_Instance && + !GetOrthancIdentifiers().HasPatientId() && + !GetOrthancIdentifiers().HasStudyId() && + !GetOrthancIdentifiers().HasSeriesId() && + GetOrthancIdentifiers().HasInstanceId()) + { + publicId = GetOrthancIdentifiers().GetInstanceId(); + return true; + } + else + { + return false; + } + } }
--- a/OrthancServer/Sources/Database/FindRequest.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/FindRequest.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -57,6 +57,12 @@ OrderingDirection_Descending }; + enum OrderingCast + { + OrderingCast_String, + OrderingCast_Int, + OrderingCast_Float + }; class Key { @@ -107,12 +113,15 @@ { private: OrderingDirection direction_; + OrderingCast cast_; Key key_; public: Ordering(const Key& key, + OrderingCast cast, OrderingDirection direction) : direction_(direction), + cast_(cast), key_(key) { } @@ -127,6 +136,11 @@ return direction_; } + OrderingCast GetCast() const + { + return cast_; + } + MetadataType GetMetadataType() const { return key_.GetMetadataType(); @@ -185,10 +199,12 @@ bool identifiers_; std::set<MetadataType> metadata_; std::set<DicomTag> mainDicomTags_; + bool count_; public: ChildrenSpecification() : - identifiers_(false) + identifiers_(false), + count_(false) { } @@ -202,6 +218,16 @@ return identifiers_; } + void SetRetrieveCount(bool retrieve) + { + count_ = retrieve; + } + + bool IsRetrieveCount() const + { + return count_; + } + void AddMetadata(MetadataType metadata) { metadata_.insert(metadata); @@ -224,7 +250,7 @@ bool IsOfInterest() const { - return (identifiers_ || !metadata_.empty() || !mainDicomTags_.empty()); + return (identifiers_ || !metadata_.empty() || !mainDicomTags_.empty() || count_); } }; @@ -245,6 +271,7 @@ bool retrieveMainDicomTags_; bool retrieveMetadata_; + bool retrieveMetadataRevisions_; bool retrieveLabels_; bool retrieveAttachments_; bool retrieveParentIdentifier_; @@ -317,9 +344,11 @@ uint64_t GetLimitsCount() const; void AddOrdering(const DicomTag& tag, + OrderingCast cast, OrderingDirection direction); void AddOrdering(MetadataType metadataType, + OrderingCast cast, OrderingDirection direction); const std::deque<Ordering*>& GetOrdering() const @@ -379,6 +408,16 @@ return retrieveMetadata_; } + void SetRetrieveMetadataRevisions(bool retrieve) + { + retrieveMetadataRevisions_ = retrieve; + } + + bool IsRetrieveMetadataRevisions() const + { + return retrieveMetadataRevisions_; + } + void SetRetrieveLabels(bool retrieve) { retrieveLabels_ = retrieve; @@ -423,5 +462,9 @@ void SetRetrieveOneInstanceMetadataAndAttachments(bool retrieve); bool IsRetrieveOneInstanceMetadataAndAttachments() const; + + bool HasConstraints() const; + + bool IsTrivialFind(std::string& publicId /* out */) const; }; }
--- a/OrthancServer/Sources/Database/FindResponse.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/FindResponse.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -333,9 +333,10 @@ void FindResponse::Resource::AddMetadata(ResourceType level, MetadataType metadata, - const std::string& value) + const std::string& value, + int64_t revision) { - std::map<MetadataType, std::string>& m = GetMetadata(level); + std::map<MetadataType, MetadataContent>& m = GetMetadata(level); if (m.find(metadata) != m.end()) { @@ -343,12 +344,12 @@ } else { - m[metadata] = value; + m[metadata] = MetadataContent(value, revision); } } - std::map<MetadataType, std::string>& FindResponse::Resource::GetMetadata(ResourceType level) + std::map<MetadataType, FindResponse::MetadataContent>& FindResponse::Resource::GetMetadata(ResourceType level) { if (!IsResourceLevelAboveOrEqual(level, level_)) { @@ -379,9 +380,9 @@ ResourceType level, MetadataType metadata) const { - const std::map<MetadataType, std::string>& m = GetMetadata(level); + const std::map<MetadataType, MetadataContent>& m = GetMetadata(level); - std::map<MetadataType, std::string>::const_iterator found = m.find(metadata); + std::map<MetadataType, MetadataContent>::const_iterator found = m.find(metadata); if (found == m.end()) { @@ -389,7 +390,29 @@ } else { - value = found->second; + value = found->second.GetValue(); + return true; + } + } + + + bool FindResponse::Resource::LookupMetadata(std::string& value, + int64_t& revision, + ResourceType level, + MetadataType metadata) const + { + const std::map<MetadataType, MetadataContent>& m = GetMetadata(level); + + std::map<MetadataType, MetadataContent>::const_iterator found = m.find(metadata); + + if (found == m.end()) + { + return false; + } + else + { + value = found->second.GetValue(); + revision = found->second.GetRevision(); return true; } } @@ -455,11 +478,14 @@ } - void FindResponse::Resource::AddAttachment(const FileInfo& attachment) + void FindResponse::Resource::AddAttachment(const FileInfo& attachment, + int64_t revision) { - if (attachments_.find(attachment.GetContentType()) == attachments_.end()) + if (attachments_.find(attachment.GetContentType()) == attachments_.end() && + revisions_.find(attachment.GetContentType()) == revisions_.end()) { attachments_[attachment.GetContentType()] = attachment; + revisions_[attachment.GetContentType()] = revision; } else { @@ -468,17 +494,48 @@ } - bool FindResponse::Resource::LookupAttachment(FileInfo& target, FileContentType type) const + bool FindResponse::Resource::LookupAttachment(FileInfo& target, + int64_t& revision, + FileContentType type) const { std::map<FileContentType, FileInfo>::const_iterator it = attachments_.find(type); + std::map<FileContentType, int64_t>::const_iterator it2 = revisions_.find(type); + if (it != attachments_.end()) { - target = it->second; - return true; + if (it2 != revisions_.end()) + { + target = it->second; + revision = it2->second; + return true; + } + else + { + throw OrthancException(ErrorCode_InternalError); + } } else { - return false; + if (it2 == revisions_.end()) + { + return false; + } + else + { + throw OrthancException(ErrorCode_InternalError); + } + } + } + + + void FindResponse::Resource::ListAttachments(std::set<FileContentType>& target) const + { + target.clear(); + + for (std::map<FileContentType, FileInfo>::const_iterator + it = attachments_.begin(); it != attachments_.end(); ++it) + { + target.insert(it->first); } } @@ -626,6 +683,18 @@ } + static void DebugMetadata(Json::Value& target, + const std::map<MetadataType, FindResponse::MetadataContent>& m) + { + target = Json::objectValue; + + for (std::map<MetadataType, FindResponse::MetadataContent>::const_iterator it = m.begin(); it != m.end(); ++it) + { + target[EnumerationToString(it->first)] = it->second.GetValue(); + } + } + + static void DebugAddAttachment(Json::Value& target, const FileInfo& info) {
--- a/OrthancServer/Sources/Database/FindResponse.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/FindResponse.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -73,10 +73,16 @@ typedef std::map<DicomTag, std::set<std::string>* > MainDicomTagValues; std::set<std::string> identifiers_; + uint64_t count_; MetadataValues metadataValues_; MainDicomTagValues mainDicomTagValues_; public: + ChildrenInformation() + : count_(0) + { + } + ~ChildrenInformation(); void AddIdentifier(const std::string& identifier); @@ -86,6 +92,21 @@ return identifiers_; } + void SetCount(uint64_t count) + { + count_ = count; + } + + void IncrementCount(uint64_t count) + { + count_ += count; + } + + uint64_t GetCount() const + { + return count_; + } + void AddMetadataValue(MetadataType metadata, const std::string& value); @@ -101,6 +122,48 @@ public: + class MetadataContent + { + private: + std::string value_; + int64_t revision_; + + public: + MetadataContent() : + revision_(0) + { + } + + MetadataContent(const std::string& value, + int64_t revision) : + value_(value), + revision_(revision) + { + } + + explicit MetadataContent(const std::string& value) : + value_(value), + revision_(0) + { + } + + const std::string& GetValue() const + { + return value_; + } + + int64_t GetRevision() const + { + return revision_; + } + + void SetRevision(int64_t revision) + { + revision_ = revision; + } + }; + + class Resource : public boost::noncopyable { private: @@ -114,15 +177,16 @@ MainDicomTagsAtLevel mainDicomTagsStudy_; MainDicomTagsAtLevel mainDicomTagsSeries_; MainDicomTagsAtLevel mainDicomTagsInstance_; - std::map<MetadataType, std::string> metadataPatient_; - std::map<MetadataType, std::string> metadataStudy_; - std::map<MetadataType, std::string> metadataSeries_; - std::map<MetadataType, std::string> metadataInstance_; + std::map<MetadataType, MetadataContent> metadataPatient_; + std::map<MetadataType, MetadataContent> metadataStudy_; + std::map<MetadataType, MetadataContent> metadataSeries_; + std::map<MetadataType, MetadataContent> metadataInstance_; ChildrenInformation childrenStudiesInformation_; ChildrenInformation childrenSeriesInformation_; ChildrenInformation childrenInstancesInformation_; std::set<std::string> labels_; std::map<FileContentType, FileInfo> attachments_; + std::map<FileContentType, int64_t> revisions_; bool hasOneInstanceMetadataAndAttachments_; std::string oneInstancePublicId_; std::map<MetadataType, std::string> oneInstanceMetadata_; @@ -199,11 +263,12 @@ void AddMetadata(ResourceType level, MetadataType metadata, - const std::string& value); + const std::string& value, + int64_t revision); - std::map<MetadataType, std::string>& GetMetadata(ResourceType level); + std::map<MetadataType, MetadataContent>& GetMetadata(ResourceType level); - const std::map<MetadataType, std::string>& GetMetadata(ResourceType level) const + const std::map<MetadataType, MetadataContent>& GetMetadata(ResourceType level) const { return const_cast<Resource&>(*this).GetMetadata(level); } @@ -212,6 +277,11 @@ ResourceType level, MetadataType metadata) const; + bool LookupMetadata(std::string& value, + int64_t& revision, + ResourceType level, + MetadataType metadata) const; + void AddChildIdentifier(ResourceType level, const std::string& childId) { @@ -223,6 +293,23 @@ return GetChildrenInformation(level).GetIdentifiers(); } + void SetChildrenCount(ResourceType level, + uint64_t count) + { + GetChildrenInformation(level).SetCount(count); + } + + void IncrementChildrenCount(ResourceType level, + uint64_t count) + { + GetChildrenInformation(level).IncrementCount(count); + } + + uint64_t GetChildrenCount(ResourceType level) const + { + return GetChildrenInformation(level).GetCount(); + } + void AddChildrenMetadataValue(ResourceType level, MetadataType metadata, const std::string& value) @@ -263,9 +350,11 @@ return labels_; } - void AddAttachment(const FileInfo& attachment); + void AddAttachment(const FileInfo& attachment, + int64_t revision); bool LookupAttachment(FileInfo& target, + int64_t& revision, FileContentType type) const; const std::map<FileContentType, FileInfo>& GetAttachments() const @@ -273,6 +362,8 @@ return attachments_; } + void ListAttachments(std::set<FileContentType>& target) const; + void SetOneInstanceMetadataAndAttachments(const std::string& instancePublicId, const std::map<MetadataType, std::string>& metadata, const std::map<FileContentType, FileInfo>& attachments);
--- a/OrthancServer/Sources/Database/IDatabaseListener.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/IDatabaseListener.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/IDatabaseWrapper.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/IDatabaseWrapper.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -111,7 +111,7 @@ { return hasAttachmentCustomDataSupport_; } - + void SetHasExtendedChanges(bool value) { hasExtendedChanges_ = value; @@ -132,7 +132,7 @@ return hasAtomicIncrementGlobalProperty_; } - void SetUpdateAndGetStatistics(bool value) + void SetHasUpdateAndGetStatistics(bool value) { hasUpdateAndGetStatistics_ = value; } @@ -214,11 +214,6 @@ virtual void GetAllPublicIds(std::list<std::string>& target, ResourceType resourceType) = 0; - virtual void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - int64_t since, - uint32_t limit) = 0; - virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/, bool& done /*out*/, int64_t since, @@ -227,9 +222,6 @@ virtual void GetChildrenInternalId(std::list<int64_t>& target, int64_t id) = 0; - virtual void GetChildrenPublicId(std::list<std::string>& target, - int64_t id) = 0; - virtual void GetExportedResources(std::list<ExportedResource>& target /*out*/, bool& done /*out*/, int64_t since, @@ -318,13 +310,6 @@ virtual bool IsDiskSizeAbove(uint64_t threshold) = 0; - virtual void ApplyLookupResources(std::list<std::string>& resourcesId, - std::list<std::string>* instancesId, // Can be NULL if not needed - const DatabaseDicomTagConstraints& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, - LabelsConstraint labelsConstraint, - uint32_t limit) = 0; // Returns "true" iff. the instance is new and has been inserted // into the database. If "false" is returned, the content of @@ -353,16 +338,6 @@ /** - * Primitives introduced in Orthanc 1.5.4 - **/ - - virtual bool LookupResourceAndParent(int64_t& id, - ResourceType& type, - std::string& parentPublicId, - const std::string& publicId) = 0; - - - /** * Primitives introduced in Orthanc 1.12.0 **/ @@ -372,10 +347,6 @@ virtual void RemoveLabel(int64_t resource, const std::string& label) = 0; - // List the labels of one single resource - virtual void ListLabels(std::set<std::string>& target, - int64_t resource) = 0; - // List all the labels that are present in any resource virtual void ListAllLabels(std::set<std::string>& target) = 0; @@ -392,10 +363,15 @@ int64_t& uncompressedSize) = 0; /** - * Primitives introduced in Orthanc 1.12.4 + * Primitives introduced in Orthanc 1.12.5 **/ // This is only implemented if "HasIntegratedFind()" is "true" + virtual void ExecuteCount(uint64_t& count, + const FindRequest& request, + const Capabilities& capabilities) = 0; + + // This is only implemented if "HasIntegratedFind()" is "true" virtual void ExecuteFind(FindResponse& response, const FindRequest& request, const Capabilities& capabilities) = 0; @@ -429,6 +405,53 @@ }; + // TODO-FIND: Could this interface be removed? + class ICompatibilityTransaction : public boost::noncopyable + { + public: + virtual ~ICompatibilityTransaction() + { + } + + virtual void GetAllPublicIdsCompatibility(std::list<std::string>& target, + ResourceType resourceType, + int64_t since, + uint32_t limit) = 0; + + virtual void GetChildrenPublicId(std::list<std::string>& target, + int64_t id) = 0; + + /** + * Primitives introduced in Orthanc 1.5.2 + **/ + + virtual void ApplyLookupResources(std::list<std::string>& resourcesId, + std::list<std::string>* instancesId, // Can be NULL if not needed + const DatabaseDicomTagConstraints& lookup, + ResourceType queryLevel, + const std::set<std::string>& labels, + LabelsConstraint labelsConstraint, + uint32_t limit) = 0; + + /** + * Primitives introduced in Orthanc 1.5.4 + **/ + + virtual bool LookupResourceAndParent(int64_t& id, + ResourceType& type, + std::string& parentPublicId, + const std::string& publicId) = 0; + + /** + * Primitives introduced in Orthanc 1.12.0 + **/ + + // List the labels of one single resource + virtual void ListLabels(std::set<std::string>& target, + int64_t resource) = 0; + }; + + virtual ~IDatabaseWrapper() { }
--- a/OrthancServer/Sources/Database/InstallLabelsTable.sql Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/InstallLabelsTable.sql Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ -- 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 +-- Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +-- Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/InstallTrackAttachmentsSize.sql Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/InstallTrackAttachmentsSize.sql Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ -- 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 +-- Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +-- Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -98,11 +98,14 @@ } - bool MainDicomTagsRegistry::NormalizeLookup(DatabaseDicomTagConstraints& target, + bool MainDicomTagsRegistry::NormalizeLookup(bool& canBeFullyPerformedInDb, + DatabaseDicomTagConstraints& target, const DatabaseLookup& source, - ResourceType queryLevel) const + ResourceType queryLevel, + bool allowChildrenExistsQueries) const { bool isEquivalentLookup = true; + canBeFullyPerformedInDb = true; target.Clear(); @@ -110,8 +113,10 @@ { ResourceType level; DicomTagType type; + const DicomTag& tag = source.GetConstraint(i).GetTag(); - LookupTag(level, type, source.GetConstraint(i).GetTag()); + LookupTag(level, type, tag); + if (type == DicomTagType_Identifier || type == DicomTagType_Main) @@ -124,6 +129,13 @@ } bool isEquivalentConstraint; + + // DicomIdentifiers are stored UPPERCASE -> as soon as a case senstive search happens, it is currently not possible to perform it in DB only + if (type == DicomTagType_Identifier && source.GetConstraint(i).IsCaseSensitive()) + { + canBeFullyPerformedInDb = false; + } + target.AddConstraint(source.GetConstraint(i).ConvertToDatabaseConstraint(isEquivalentConstraint, level, type)); if (!isEquivalentConstraint) @@ -133,7 +145,26 @@ } else { - isEquivalentLookup = false; + if (allowChildrenExistsQueries && + tag == DICOM_TAG_MODALITIES_IN_STUDY && queryLevel == ResourceType_Study) + { + // transform the query into a children query + std::vector<std::string> values(source.GetConstraint(i).GetValues().begin(), source.GetConstraint(i).GetValues().end()); + + std::unique_ptr<DatabaseDicomTagConstraint> constraint(new DatabaseDicomTagConstraint(ResourceType_Series, + DICOM_TAG_MODALITY, + false, + ConstraintType_List, + values, + false, + true)); + target.AddConstraint(constraint.release()); + } + else + { + isEquivalentLookup = false; + canBeFullyPerformedInDb = false; + } } }
--- a/OrthancServer/Sources/Database/MainDicomTagsRegistry.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/MainDicomTagsRegistry.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -82,8 +82,10 @@ * constraints are less strict than the original DatabaseLookup, * so more resources will match them. **/ - bool NormalizeLookup(DatabaseDicomTagConstraints& target, + bool NormalizeLookup(bool& canBeFullyPerformedInDb, + DatabaseDicomTagConstraints& target, const DatabaseLookup& source, - ResourceType queryLevel) const; + ResourceType queryLevel, + bool allowChildrenExistsQueries) const; }; }
--- a/OrthancServer/Sources/Database/OrthancIdentifiers.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/OrthancIdentifiers.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/OrthancIdentifiers.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/OrthancIdentifiers.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/PrepareDatabase.sql Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/PrepareDatabase.sql Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ -- 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 +-- Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +-- Copyright (C) 2021-2025 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 @@ -40,6 +40,9 @@ ); -- The following table was added in Orthanc 0.8.5 (database v5) +-- It contains only the DICOM Tags that are commonly used for searches. +-- All these tags are converted to UPPERCASE ! +-- These tags are also stored in the MainDicomTags table without casing modificiation. CREATE TABLE DicomIdentifiers( id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, tagGroup INTEGER, @@ -52,7 +55,7 @@ id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, type INTEGER, value TEXT, - -- revision INTEGER, -- New in Orthanc 1.12.0 (added in InstallRevisionAndCustomData.sql) + -- revision INTEGER, -- New in Orthanc 1.12.7 (added in InstallRevisionAndCustomData.sql) PRIMARY KEY(id, type) ); @@ -65,8 +68,8 @@ compressionType INTEGER, uncompressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) compressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) - -- revision INTEGER, -- New in Orthanc 1.12.0 (added in InstallRevisionAndCustomData.sql) - -- customData TEXT, -- New in Orthanc 1.12.0 (added in InstallRevisionAndCustomData.sql) + -- revision INTEGER, -- New in Orthanc 1.12.7 (added in InstallRevisionAndCustomData.sql) + -- customData TEXT, -- New in Orthanc 1.12.7 (added in InstallRevisionAndCustomData.sql) PRIMARY KEY(id, fileType) );
--- a/OrthancServer/Sources/Database/ResourcesContent.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/ResourcesContent.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/ResourcesContent.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/ResourcesContent.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -480,8 +480,9 @@ #define C6_STRING_4 6 #define C7_INT_1 7 #define C8_INT_2 8 -#define C9_BIG_INT_1 9 -#define C10_BIG_INT_2 10 +#define C9_INT_3 9 +#define C10_BIG_INT_1 10 +#define C11_BIG_INT_2 11 #define QUERY_LOOKUP 1 #define QUERY_MAIN_DICOM_TAGS 2 @@ -496,10 +497,13 @@ #define QUERY_CHILDREN_IDENTIFIERS 20 #define QUERY_CHILDREN_MAIN_DICOM_TAGS 21 #define QUERY_CHILDREN_METADATA 22 +#define QUERY_CHILDREN_COUNT 23 #define QUERY_GRAND_CHILDREN_IDENTIFIERS 30 #define QUERY_GRAND_CHILDREN_MAIN_DICOM_TAGS 31 #define QUERY_GRAND_CHILDREN_METADATA 32 +#define QUERY_GRAND_CHILDREN_COUNT 33 #define QUERY_GRAND_GRAND_CHILDREN_IDENTIFIERS 40 +#define QUERY_GRAND_GRAND_CHILDREN_COUNT 41 #define QUERY_ONE_INSTANCE_IDENTIFIER 50 #define QUERY_ONE_INSTANCE_METADATA 51 #define QUERY_ONE_INSTANCE_ATTACHMENTS 52 @@ -507,6 +511,25 @@ #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) + virtual void ExecuteCount(uint64_t& count, + const FindRequest& request, + const Capabilities& capabilities) ORTHANC_OVERRIDE + { + LookupFormatter formatter; + std::string sql; + + std::string lookupSql; + LookupFormatter::Apply(lookupSql, formatter, request); + + // base query, retrieve the ordered internalId and publicId of the selected resources + sql = "WITH Lookup AS (" + lookupSql + ") SELECT COUNT(*) FROM Lookup"; + SQLite::Statement s(db_, SQLITE_FROM_HERE_DYNAMIC(sql), sql); + formatter.Bind(s); + + s.Step(); + count = s.ColumnInt64(0); + } + virtual void ExecuteFind(FindResponse& response, const FindRequest& request, @@ -574,8 +597,9 @@ " NULL AS c6_string4, " " NULL AS c7_int1, " " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " " FROM Lookup "; // need one instance info ? (part 2: execute the queries) @@ -592,8 +616,9 @@ " NULL AS c6_string4, " " NULL AS c7_int1, " " NULL AS c8_int2, " - " instanceInternalId AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " instanceInternalId AS c10_big_int1, " + " NULL AS c11_big_int2 " " FROM OneInstance "; sql += " UNION SELECT" @@ -606,8 +631,9 @@ " NULL AS c6_string4, " " Metadata.type AS c7_int1, " " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " " FROM OneInstance " " INNER JOIN Metadata ON Metadata.id = OneInstance.instanceInternalId "; @@ -621,8 +647,9 @@ " customData AS c6_string4, " " fileType AS c7_int1, " " compressionType AS c8_int2, " - " compressedSize AS c9_big_int1, " - " uncompressedSize AS c10_big_int2 " + " revision AS c9_int3, " + " compressedSize AS c10_big_int1, " + " uncompressedSize AS c11_big_int2 " " FROM OneInstance " " INNER JOIN AttachedFiles ON AttachedFiles.id = OneInstance.instanceInternalId "; @@ -641,8 +668,9 @@ " NULL AS c6_string4, " " tagGroup AS c7_int1, " " tagElement AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN MainDicomTags ON MainDicomTags.id = Lookup.internalId "; } @@ -659,9 +687,10 @@ " NULL AS c5_string3, " " NULL AS c6_string4, " " type AS c7_int1, " - " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " revision AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Metadata ON Metadata.id = Lookup.internalId "; } @@ -679,8 +708,9 @@ " customData AS c6_string4, " " fileType AS c7_int1, " " compressionType AS c8_int2, " - " compressedSize AS c9_big_int1, " - " uncompressedSize AS c10_big_int2 " + " revision AS c9_int3, " + " compressedSize AS c10_big_int1, " + " uncompressedSize AS c11_big_int2 " "FROM Lookup " "INNER JOIN AttachedFiles ON AttachedFiles.id = Lookup.internalId "; } @@ -699,8 +729,9 @@ " NULL AS c6_string4, " " NULL AS c7_int1, " " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Labels ON Labels.id = Lookup.internalId "; } @@ -720,8 +751,9 @@ " NULL AS c6_string4, " " tagGroup AS c7_int1, " " tagElement AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " "INNER JOIN MainDicomTags ON MainDicomTags.id = currentLevel.parentId "; @@ -739,9 +771,10 @@ " NULL AS c5_string3, " " NULL AS c6_string4, " " type AS c7_int1, " - " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " revision AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " "INNER JOIN Metadata ON Metadata.id = currentLevel.parentId "; @@ -762,8 +795,9 @@ " NULL AS c6_string4, " " tagGroup AS c7_int1, " " tagElement AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " "INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId " @@ -782,9 +816,10 @@ " NULL AS c5_string3, " " NULL AS c6_string4, " " type AS c7_int1, " - " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " revision AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Resources currentLevel ON Lookup.internalId = currentLevel.internalId " "INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId " @@ -806,8 +841,9 @@ " NULL AS c6_string4, " " tagGroup AS c7_int1, " " tagElement AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " " INNER JOIN MainDicomTags ON MainDicomTags.id = childLevel.internalId AND " + JoinRequestedTags(request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1))); @@ -826,8 +862,9 @@ " NULL AS c6_string4, " " tagGroup AS c7_int1, " " tagElement AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " " INNER JOIN Resources grandChildLevel ON grandChildLevel.parentId = childLevel.internalId " @@ -847,8 +884,9 @@ " NULL AS c6_string4, " " NULL AS c7_int1, " " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " " INNER JOIN Resources currentLevel ON currentLevel.internalId = Lookup.internalId " " INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId "; @@ -866,9 +904,10 @@ " NULL AS c5_string3, " " NULL AS c6_string4, " " type AS c7_int1, " - " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " revision AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " " INNER JOIN Metadata ON Metadata.id = childLevel.internalId AND Metadata.type IN (" + JoinRequestedMetadata(request.GetChildrenSpecification(static_cast<ResourceType>(requestLevel + 1))) + ") "; @@ -886,9 +925,10 @@ " NULL AS c5_string3, " " NULL AS c6_string4, " " type AS c7_int1, " - " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " revision AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " " INNER JOIN Resources childLevel ON childLevel.parentId = Lookup.internalId " " INNER JOIN Resources grandChildLevel ON grandChildLevel.parentId = childLevel.internalId " @@ -910,11 +950,33 @@ " NULL AS c6_string4, " " NULL AS c7_int1, " " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " " INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId "; } + // no need to count if we have retrieved the list of identifiers + else if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Study).IsRetrieveCount()) || + (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveCount()) || + (requestLevel == ResourceType_Series && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveCount())) + { + sql += "UNION SELECT " + " " TOSTRING(QUERY_CHILDREN_COUNT) " AS c0_queryId, " + " Lookup.internalId AS c1_internalId, " + " NULL AS c2_rowNumber, " + " NULL AS c3_string1, " + " NULL AS c4_string2, " + " NULL AS c5_string3, " + " NULL AS c6_string4, " + " COUNT(*) AS c7_int1, " + " NULL AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " + "FROM Lookup " + " INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId GROUP BY Lookup.internalId "; + } // need grandchildren identifiers ? if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) || @@ -930,12 +992,34 @@ " NULL AS c6_string4, " " NULL AS c7_int1, " " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId " "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId "; } + // no need to count if we have retrieved the list of identifiers + else if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveCount()) || + (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveCount())) + { + sql += "UNION SELECT " + " " TOSTRING(QUERY_GRAND_CHILDREN_COUNT) " AS c0_queryId, " + " Lookup.internalId AS c1_internalId, " + " NULL AS c2_rowNumber, " + " NULL AS c3_string1, " + " NULL AS c4_string2, " + " NULL AS c5_string3, " + " NULL AS c6_string4, " + " COUNT(*) AS c7_int1, " + " NULL AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " + "FROM Lookup " + "INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId " + "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId GROUP BY Lookup.internalId "; + } // need grandgrandchildren identifiers ? if (requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers()) @@ -950,13 +1034,35 @@ " NULL AS c6_string4, " " NULL AS c7_int1, " " NULL AS c8_int2, " - " NULL AS c9_big_int1, " - " NULL AS c10_big_int2 " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " "FROM Lookup " "INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId " "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId " "INNER JOIN Resources grandGrandChildLevel ON grandChildLevel.internalId = grandGrandChildLevel.parentId "; } + // no need to count if we have retrieved the list of identifiers + else if (requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveCount()) + { + sql += "UNION SELECT " + " " TOSTRING(QUERY_GRAND_GRAND_CHILDREN_COUNT) " AS c0_queryId, " + " Lookup.internalId AS c1_internalId, " + " NULL AS c2_rowNumber, " + " NULL AS c3_string1, " + " NULL AS c4_string2, " + " NULL AS c5_string3, " + " NULL AS c6_string4, " + " COUNT(*) AS c7_int1, " + " NULL AS c8_int2, " + " NULL AS c9_int3, " + " NULL AS c10_big_int1, " + " NULL AS c11_big_int2 " + "FROM Lookup " + "INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId " + "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId " + "INNER JOIN Resources grandGrandChildLevel ON grandChildLevel.internalId = grandGrandChildLevel.parentId GROUP BY Lookup.internalId "; + } sql += " ORDER BY c0_queryId, c2_rowNumber"; // this is really important to make sure that the Lookup query is the first one to provide results since we use it to create the responses element ! @@ -989,11 +1095,11 @@ case QUERY_ATTACHMENTS: { FindResponse::Resource& res = response.GetResourceByInternalId(internalId); - FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C7_INT_1)), - s.ColumnInt64(C9_BIG_INT_1), s.ColumnString(C4_STRING_2), + FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C7_INT_1)), + s.ColumnInt64(C11_BIG_INT_2), s.ColumnString(C4_STRING_2), static_cast<CompressionType>(s.ColumnInt(C8_INT_2)), - s.ColumnInt64(C10_BIG_INT_2), s.ColumnString(C5_STRING_3), s.ColumnString(C6_STRING_4)); - res.AddAttachment(file); + s.ColumnInt64(C10_BIG_INT_1), s.ColumnString(C5_STRING_3), s.ColumnString(C6_STRING_4)); + res.AddAttachment(file, s.ColumnInt(C9_INT_3)); }; break; case QUERY_MAIN_DICOM_TAGS: @@ -1044,7 +1150,7 @@ FindResponse::Resource& res = response.GetResourceByInternalId(internalId); res.AddMetadata(static_cast<ResourceType>(requestLevel), static_cast<MetadataType>(s.ColumnInt(C7_INT_1)), - s.ColumnString(C3_STRING_1)); + s.ColumnString(C3_STRING_1), s.ColumnInt(C8_INT_2)); }; break; case QUERY_PARENT_METADATA: @@ -1052,7 +1158,7 @@ FindResponse::Resource& res = response.GetResourceByInternalId(internalId); res.AddMetadata(static_cast<ResourceType>(requestLevel - 1), static_cast<MetadataType>(s.ColumnInt(C7_INT_1)), - s.ColumnString(C3_STRING_1)); + s.ColumnString(C3_STRING_1), s.ColumnInt(C8_INT_2)); }; break; case QUERY_GRAND_PARENT_METADATA: @@ -1060,7 +1166,7 @@ FindResponse::Resource& res = response.GetResourceByInternalId(internalId); res.AddMetadata(static_cast<ResourceType>(requestLevel - 2), static_cast<MetadataType>(s.ColumnInt(C7_INT_1)), - s.ColumnString(C3_STRING_1)); + s.ColumnString(C3_STRING_1), s.ColumnInt(C8_INT_2)); }; break; case QUERY_CHILDREN_METADATA: @@ -1090,6 +1196,8 @@ FindResponse::Resource& res = response.GetResourceByInternalId(internalId); res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 1), s.ColumnString(C3_STRING_1)); + res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 1), + res.GetChildrenIdentifiers(static_cast<ResourceType>(requestLevel + 1)).size()); }; break; case QUERY_GRAND_CHILDREN_IDENTIFIERS: @@ -1097,6 +1205,8 @@ FindResponse::Resource& res = response.GetResourceByInternalId(internalId); res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 2), s.ColumnString(C3_STRING_1)); + res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 2), + res.GetChildrenIdentifiers(static_cast<ResourceType>(requestLevel + 2)).size()); }; break; case QUERY_GRAND_GRAND_CHILDREN_IDENTIFIERS: @@ -1104,6 +1214,29 @@ FindResponse::Resource& res = response.GetResourceByInternalId(internalId); res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 3), s.ColumnString(C3_STRING_1)); + res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 3), + res.GetChildrenIdentifiers(static_cast<ResourceType>(requestLevel + 3)).size()); + }; break; + + case QUERY_CHILDREN_COUNT: + { + FindResponse::Resource& res = response.GetResourceByInternalId(internalId); + res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 1), + static_cast<uint64_t>(s.ColumnInt64(C7_INT_1))); + }; break; + + case QUERY_GRAND_CHILDREN_COUNT: + { + FindResponse::Resource& res = response.GetResourceByInternalId(internalId); + res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 2), + static_cast<uint64_t>(s.ColumnInt64(C7_INT_1))); + }; break; + + case QUERY_GRAND_GRAND_CHILDREN_COUNT: + { + FindResponse::Resource& res = response.GetResourceByInternalId(internalId); + res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 3), + static_cast<uint64_t>(s.ColumnInt64(C7_INT_1))); }; break; case QUERY_ONE_INSTANCE_IDENTIFIER: @@ -1121,10 +1254,10 @@ case QUERY_ONE_INSTANCE_ATTACHMENTS: { FindResponse::Resource& res = response.GetResourceByInternalId(internalId); - FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C7_INT_1)), - s.ColumnInt64(C9_BIG_INT_1), s.ColumnString(C4_STRING_2), + FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C7_INT_1)), + s.ColumnInt64(C11_BIG_INT_2), s.ColumnString(C4_STRING_2), static_cast<CompressionType>(s.ColumnInt(C8_INT_2)), - s.ColumnInt64(C10_BIG_INT_2), s.ColumnString(C5_STRING_3), s.ColumnString(C6_STRING_4)); + s.ColumnInt64(C10_BIG_INT_1), s.ColumnString(C5_STRING_3), s.ColumnString(C6_STRING_4)); res.AddOneInstanceAttachment(file); }; break; @@ -1284,10 +1417,10 @@ } - virtual void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - int64_t since, - uint32_t limit) ORTHANC_OVERRIDE + virtual void GetAllPublicIdsCompatibility(std::list<std::string>& target, + ResourceType resourceType, + int64_t since, + uint32_t limit) ORTHANC_OVERRIDE { SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE " @@ -2167,7 +2300,7 @@ dbCapabilities_.SetFlushToDisk(true); dbCapabilities_.SetLabelsSupport(true); dbCapabilities_.SetHasExtendedChanges(true); - dbCapabilities_.SetHasFindSupport(true); + dbCapabilities_.SetHasFindSupport(HasIntegratedFind()); db_.Open(path); } @@ -2181,7 +2314,7 @@ dbCapabilities_.SetFlushToDisk(true); dbCapabilities_.SetLabelsSupport(true); dbCapabilities_.SetHasExtendedChanges(true); - dbCapabilities_.SetHasFindSupport(true); + dbCapabilities_.SetHasFindSupport(HasIntegratedFind()); db_.OpenInMemory(); } @@ -2281,7 +2414,7 @@ } } - // New in Orthanc 1.12.5 + // New in Orthanc 1.12.7 if (version_ >= 6) { if (!transaction->LookupGlobalProperty(tmp, GlobalProperty_SQLiteHasCustomDataAndRevision, true /* unused in SQLite */)
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -23,7 +23,7 @@ #pragma once -#include "BaseDatabaseWrapper.h" +#include "BaseCompatibilityTransaction.h" #include "../../../OrthancFramework/Sources/SQLite/Connection.h" @@ -36,7 +36,7 @@ * translates low-level requests into SQL statements. Mutual * exclusion MUST be implemented at a higher level. **/ - class SQLiteDatabaseWrapper : public BaseDatabaseWrapper + class SQLiteDatabaseWrapper : public IDatabaseWrapper { private: class TransactionBase; @@ -112,7 +112,7 @@ * "UnitTestsTransaction" give access to additional information * about the underlying SQLite database to be used in unit tests. **/ - class UnitTestsTransaction : public BaseDatabaseWrapper::BaseTransaction + class UnitTestsTransaction : public BaseCompatibilityTransaction { protected: SQLite::Connection& db_;
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -288,22 +288,6 @@ } - static void CopyListToVector(std::vector<std::string>& target, - const std::list<std::string>& source) - { - target.resize(source.size()); - - size_t pos = 0; - - for (std::list<std::string>::const_iterator - it = source.begin(); it != source.end(); ++it) - { - target[pos] = *it; - pos ++; - } - } - - void StatelessDatabaseOperations::ReadWriteTransaction::LogChange(int64_t internalId, ChangeType changeType, ResourceType resourceType, @@ -580,284 +564,32 @@ { ApplyInternal(NULL, &operations); } - - - bool StatelessDatabaseOperations::ExpandResource(ExpandedResource& target, - const std::string& publicId, - ResourceType level, - const std::set<DicomTag>& requestedTags, - ExpandResourceFlags expandFlags) - { - class Operations : public ReadOnlyOperationsT6< - bool&, ExpandedResource&, const std::string&, ResourceType, const std::set<DicomTag>&, ExpandResourceFlags> + + + const FindResponse::Resource& StatelessDatabaseOperations::ExecuteSingleResource(FindResponse& response, + const FindRequest& request) + { + ExecuteFind(response, request); + + if (response.GetSize() == 0) { - private: - bool hasLabelsSupport_; - - static bool LookupStringMetadata(std::string& result, - const std::map<MetadataType, std::string>& metadata, - MetadataType type) - { - std::map<MetadataType, std::string>::const_iterator found = metadata.find(type); - - if (found == metadata.end()) - { - return false; - } - else - { - result = found->second; - return true; - } - } - - - static bool LookupIntegerMetadata(int64_t& result, - const std::map<MetadataType, std::string>& metadata, - MetadataType type) - { - std::string s; - if (!LookupStringMetadata(s, metadata, type)) - { - return false; - } - - try - { - result = boost::lexical_cast<int64_t>(s); - return true; - } - catch (boost::bad_lexical_cast&) - { - return false; - } - } - - - public: - explicit Operations(bool hasLabelsSupport) : - hasLabelsSupport_(hasLabelsSupport) - { - } - - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE + throw OrthancException(ErrorCode_UnknownResource); + } + else if (response.GetSize() == 1) + { + if (response.GetResourceByIndex(0).GetLevel() != request.GetLevel()) { - // Lookup for the requested resource - int64_t internalId; - ResourceType type; - std::string parent; - if (!transaction.LookupResourceAndParent(internalId, type, parent, tuple.get<2>()) || - type != tuple.get<3>()) - { - tuple.get<0>() = false; - } - else - { - ExpandedResource& target = tuple.get<1>(); - ExpandResourceFlags expandFlags = tuple.get<5>(); - - // Set information about the parent resource (if it exists) - if (type == ResourceType_Patient) - { - if (!parent.empty()) - { - throw OrthancException(ErrorCode_DatabasePlugin); - } - } - else - { - if (parent.empty()) - { - throw OrthancException(ErrorCode_DatabasePlugin); - } - - target.parentId_ = parent; - } - - target.SetResource(type, tuple.get<2>()); - - if (expandFlags & ExpandResourceFlags_IncludeChildren) - { - // List the children resources - transaction.GetChildrenPublicId(target.childrenIds_, internalId); - } - - if (expandFlags & ExpandResourceFlags_IncludeMetadata) - { - // Extract the metadata - transaction.GetAllMetadata(target.metadata_, internalId); - - switch (type) - { - case ResourceType_Patient: - case ResourceType_Study: - break; - - case ResourceType_Series: - { - int64_t i; - if (LookupIntegerMetadata(i, target.metadata_, MetadataType_Series_ExpectedNumberOfInstances)) - { - target.expectedNumberOfInstances_ = static_cast<int>(i); - target.status_ = EnumerationToString(transaction.GetSeriesStatus(internalId, i)); - } - else - { - target.expectedNumberOfInstances_ = -1; - target.status_ = EnumerationToString(SeriesStatus_Unknown); - } - - break; - } - - case ResourceType_Instance: - { - FileInfo attachment; - int64_t revision; // ignored - if (!transaction.LookupAttachment(attachment, revision, internalId, FileContentType_Dicom)) - { - throw OrthancException(ErrorCode_InternalError); - } - - target.fileSize_ = static_cast<unsigned int>(attachment.GetUncompressedSize()); - target.fileUuid_ = attachment.GetUuid(); - - int64_t i; - if (LookupIntegerMetadata(i, target.metadata_, MetadataType_Instance_IndexInSeries)) - { - target.indexInSeries_ = static_cast<int>(i); - } - else - { - target.indexInSeries_ = -1; - } - - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - // check the main dicom tags list has not changed since the resource was stored - target.mainDicomTagsSignature_ = DicomMap::GetDefaultMainDicomTagsSignatureFrom1_11(type); - LookupStringMetadata(target.mainDicomTagsSignature_, target.metadata_, MetadataType_MainDicomTagsSignature); - } - - if (expandFlags & ExpandResourceFlags_IncludeMainDicomTags) - { - // read all tags from DB - transaction.GetMainDicomTags(target.GetMainDicomTags(), internalId); - - // read all main sequences from DB - std::string serializedSequences; - if (LookupStringMetadata(serializedSequences, target.metadata_, MetadataType_MainDicomSequences)) - { - Json::Value jsonMetadata; - Toolbox::ReadJson(jsonMetadata, serializedSequences); - - assert(jsonMetadata["Version"].asInt() == 1); - target.GetMainDicomTags().FromDicomAsJson(jsonMetadata["Sequences"], true /* append */, true /* parseSequences */); - } - - // check if we have access to all requestedTags or if we must get tags from parents - const std::set<DicomTag>& requestedTags = tuple.get<4>(); - - if (requestedTags.size() > 0) - { - std::set<DicomTag> savedMainDicomTags; - - FromDcmtkBridge::ParseListOfTags(savedMainDicomTags, target.mainDicomTagsSignature_); - - // read parent main dicom tags as long as we have not gathered all requested tags - ResourceType currentLevel = target.GetLevel(); - int64_t currentInternalId = internalId; - Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); - - while ((target.missingRequestedTags_.size() > 0) - && currentLevel != ResourceType_Patient) - { - currentLevel = GetParentResourceType(currentLevel); - - int64_t currentParentId; - if (!transaction.LookupParent(currentParentId, currentInternalId)) - { - break; - } - - std::map<MetadataType, std::string> parentMetadata; - transaction.GetAllMetadata(parentMetadata, currentParentId); - - std::string parentMainDicomTagsSignature = DicomMap::GetDefaultMainDicomTagsSignatureFrom1_11(currentLevel); - LookupStringMetadata(parentMainDicomTagsSignature, parentMetadata, MetadataType_MainDicomTagsSignature); - - std::set<DicomTag> parentSavedMainDicomTags; - FromDcmtkBridge::ParseListOfTags(parentSavedMainDicomTags, parentMainDicomTagsSignature); - - size_t previousMissingCount = target.missingRequestedTags_.size(); - Toolbox::AppendSets(savedMainDicomTags, parentSavedMainDicomTags); - Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); - - // read the parent tags from DB only if it reduces the number of missing tags - if (target.missingRequestedTags_.size() < previousMissingCount) - { - Toolbox::AppendSets(savedMainDicomTags, parentSavedMainDicomTags); - - DicomMap parentTags; - transaction.GetMainDicomTags(parentTags, currentParentId); - - target.GetMainDicomTags().Merge(parentTags); - } - - currentInternalId = currentParentId; - } - } - } - - if ((expandFlags & ExpandResourceFlags_IncludeLabels) && - hasLabelsSupport_) - { - transaction.ListLabels(target.labels_, internalId); - } - - std::string tmp; - - if (LookupStringMetadata(tmp, target.metadata_, MetadataType_AnonymizedFrom)) - { - target.anonymizedFrom_ = tmp; - } - - if (LookupStringMetadata(tmp, target.metadata_, MetadataType_ModifiedFrom)) - { - target.modifiedFrom_ = tmp; - } - - if (type == ResourceType_Patient || - type == ResourceType_Study || - type == ResourceType_Series) - { - target.isStable_ = !transaction.GetTransactionContext().IsUnstableResource(type, internalId); - - if (LookupStringMetadata(tmp, target.metadata_, MetadataType_LastUpdate)) - { - target.lastUpdate_ = tmp; - } - } - else - { - target.isStable_ = false; - } - - tuple.get<0>() = true; - } + throw OrthancException(ErrorCode_DatabasePlugin); + } + else + { + return response.GetResourceByIndex(0); } - }; - - bool found; - Operations operations(db_.GetDatabaseCapabilities().HasLabelsSupport()); - operations.Apply(*this, found, target, publicId, level, requestedTags, expandFlags); - return found; + } + else + { + throw OrthancException(ErrorCode_DatabasePlugin); + } } @@ -865,110 +597,50 @@ const std::string& publicId, ResourceType level) { - class Operations : public ReadOnlyOperationsT3<std::map<MetadataType, std::string>&, const std::string&, ResourceType> + FindRequest request(level); + request.SetOrthancId(level, publicId); + request.SetRetrieveMetadata(true); + + FindResponse response; + std::map<MetadataType, FindResponse::MetadataContent> metadata = ExecuteSingleResource(response, request).GetMetadata(level); + + target.clear(); + for (std::map<MetadataType, FindResponse::MetadataContent>::const_iterator + it = metadata.begin(); it != metadata.end(); ++it) { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - ResourceType type; - int64_t id; - if (!transaction.LookupResource(id, type, tuple.get<1>()) || - tuple.get<2>() != type) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else - { - transaction.GetAllMetadata(tuple.get<0>(), id); - } - } - }; - - Operations operations; - operations.Apply(*this, target, publicId, level); + target[it->first] = it->second.GetValue(); + } } bool StatelessDatabaseOperations::LookupAttachment(FileInfo& attachment, int64_t& revision, - const std::string& instancePublicId, + ResourceType level, + const std::string& publicId, FileContentType contentType) { - class Operations : public ReadOnlyOperationsT5<bool&, FileInfo&, int64_t&, const std::string&, FileContentType> - { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - int64_t internalId; - ResourceType type; - if (!transaction.LookupResource(internalId, type, tuple.get<3>())) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else if (transaction.LookupAttachment(tuple.get<1>(), tuple.get<2>(), internalId, tuple.get<4>())) - { - assert(tuple.get<1>().GetContentType() == tuple.get<4>()); - tuple.get<0>() = true; - } - else - { - tuple.get<0>() = false; - } - } - }; - - bool found; - Operations operations; - operations.Apply(*this, found, attachment, revision, instancePublicId, contentType); - return found; + FindRequest request(level); + request.SetOrthancId(level, publicId); + request.SetRetrieveAttachments(true); + + FindResponse response; + return ExecuteSingleResource(response, request).LookupAttachment(attachment, revision, contentType); } void StatelessDatabaseOperations::GetAllUuids(std::list<std::string>& target, ResourceType resourceType) { - class Operations : public ReadOnlyOperationsT2<std::list<std::string>&, ResourceType> + // This method is tested by "orthanc-tests/Plugins/WebDav/Run.py" + FindRequest request(resourceType); + + FindResponse response; + ExecuteFind(response, request); + + target.clear(); + for (size_t i = 0; i < response.GetSize(); i++) { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - // TODO - CANDIDATE FOR "TransactionType_Implicit" - transaction.GetAllPublicIds(tuple.get<0>(), tuple.get<1>()); - } - }; - - Operations operations; - operations.Apply(*this, target, resourceType); - } - - - void StatelessDatabaseOperations::GetAllUuids(std::list<std::string>& target, - ResourceType resourceType, - size_t since, - uint32_t limit) - { - if (limit == 0) - { - target.clear(); - } - else - { - class Operations : public ReadOnlyOperationsT4<std::list<std::string>&, ResourceType, size_t, size_t> - { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - // TODO - CANDIDATE FOR "TransactionType_Implicit" - transaction.GetAllPublicIds(tuple.get<0>(), tuple.get<1>(), tuple.get<2>(), tuple.get<3>()); - } - }; - - Operations operations; - operations.Apply(*this, target, resourceType, since, limit); + target.push_back(response.GetResourceByIndex(i).GetIdentifier()); } } @@ -1232,104 +904,85 @@ void StatelessDatabaseOperations::GetChildren(std::list<std::string>& result, + ResourceType level, const std::string& publicId) { - class Operations : public ReadOnlyOperationsT2<std::list<std::string>&, const std::string&> + const ResourceType childLevel = GetChildResourceType(level); + + FindRequest request(level); + request.SetOrthancId(level, publicId); + request.GetChildrenSpecification(childLevel).SetRetrieveIdentifiers(true); + + FindResponse response; + ExecuteFind(response, request); + + result.clear(); + + for (size_t i = 0; i < response.GetSize(); i++) { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE + const std::set<std::string>& children = response.GetResourceByIndex(i).GetChildrenIdentifiers(childLevel); + + for (std::set<std::string>::const_iterator it = children.begin(); it != children.end(); ++it) { - ResourceType type; - int64_t resource; - if (!transaction.LookupResource(resource, type, tuple.get<1>())) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else if (type == ResourceType_Instance) - { - // An instance cannot have a child - throw OrthancException(ErrorCode_BadParameterType); - } - else - { - std::list<int64_t> tmp; - transaction.GetChildrenInternalId(tmp, resource); - - tuple.get<0>().clear(); - - for (std::list<int64_t>::const_iterator - it = tmp.begin(); it != tmp.end(); ++it) - { - tuple.get<0>().push_back(transaction.GetPublicId(*it)); - } - } + result.push_back(*it); } - }; - - Operations operations; - operations.Apply(*this, result, publicId); + } + } + + + void StatelessDatabaseOperations::GetChildInstances(std::list<std::string>& result, + const std::string& publicId, + ResourceType level) + { + result.clear(); + if (level == ResourceType_Instance) + { + result.push_back(publicId); + } + else + { + FindRequest request(level); + request.SetOrthancId(level, publicId); + request.GetChildrenSpecification(ResourceType_Instance).SetRetrieveIdentifiers(true); + + FindResponse response; + const std::set<std::string>& instances = ExecuteSingleResource(response, request).GetChildrenIdentifiers(ResourceType_Instance); + + for (std::set<std::string>::const_iterator it = instances.begin(); it != instances.end(); ++it) + { + result.push_back(*it); + } + } } void StatelessDatabaseOperations::GetChildInstances(std::list<std::string>& result, const std::string& publicId) { - class Operations : public ReadOnlyOperationsT2<std::list<std::string>&, const std::string&> + ResourceType level; + if (LookupResourceType(level, publicId)) + { + GetChildInstances(result, publicId, level); + } + else { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - tuple.get<0>().clear(); - - ResourceType type; - int64_t top; - if (!transaction.LookupResource(top, type, tuple.get<1>())) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else if (type == ResourceType_Instance) - { - // The resource is already an instance: Do not go down the hierarchy - tuple.get<0>().push_back(tuple.get<1>()); - } - else - { - std::stack<int64_t> toExplore; - toExplore.push(top); - - std::list<int64_t> tmp; - while (!toExplore.empty()) - { - // Get the internal ID of the current resource - int64_t resource = toExplore.top(); - toExplore.pop(); - - // TODO - This could be optimized by seeing how many - // levels "type == transaction.GetResourceType(top)" is - // above the "instances level" - if (transaction.GetResourceType(resource) == ResourceType_Instance) - { - tuple.get<0>().push_back(transaction.GetPublicId(resource)); - } - else - { - // Tag all the children of this resource as to be explored - transaction.GetChildrenInternalId(tmp, resource); - for (std::list<int64_t>::const_iterator - it = tmp.begin(); it != tmp.end(); ++it) - { - toExplore.push(*it); - } - } - } - } - } - }; - - Operations operations; - operations.Apply(*this, result, publicId); + throw OrthancException(ErrorCode_UnknownResource); + } + } + + + bool StatelessDatabaseOperations::LookupMetadata(std::string& target, + const std::string& publicId, + ResourceType expectedType, + MetadataType type) + { + FindRequest request(expectedType); + request.SetOrthancId(expectedType, publicId); + request.SetRetrieveMetadata(true); + request.SetRetrieveMetadataRevisions(false); // No need to retrieve revisions + + FindResponse response; + return ExecuteSingleResource(response, request).LookupMetadata(target, expectedType, type); } @@ -1339,31 +992,13 @@ ResourceType expectedType, MetadataType type) { - class Operations : public ReadOnlyOperationsT6<bool&, std::string&, int64_t&, - const std::string&, ResourceType, MetadataType> - { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - ResourceType resourceType; - int64_t id; - if (!transaction.LookupResource(id, resourceType, tuple.get<3>()) || - resourceType != tuple.get<4>()) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else - { - tuple.get<0>() = transaction.LookupMetadata(tuple.get<1>(), tuple.get<2>(), id, tuple.get<5>()); - } - } - }; - - bool found; - Operations operations; - operations.Apply(*this, found, target, revision, publicId, expectedType, type); - return found; + FindRequest request(expectedType); + request.SetOrthancId(expectedType, publicId); + request.SetRetrieveMetadata(true); + request.SetRetrieveMetadataRevisions(true); // We are asked to retrieve revisions + + FindResponse response; + return ExecuteSingleResource(response, request).LookupMetadata(target, revision, expectedType, type); } @@ -1371,28 +1006,12 @@ const std::string& publicId, ResourceType expectedType) { - class Operations : public ReadOnlyOperationsT3<std::set<FileContentType>&, const std::string&, ResourceType> - { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - ResourceType type; - int64_t id; - if (!transaction.LookupResource(id, type, tuple.get<1>()) || - tuple.get<2>() != type) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else - { - transaction.ListAvailableAttachments(tuple.get<0>(), id); - } - } - }; - - Operations operations; - operations.Apply(*this, target, publicId, expectedType); + FindRequest request(expectedType); + request.SetOrthancId(expectedType, publicId); + request.SetRetrieveAttachments(true); + + FindResponse response; + ExecuteSingleResource(response, request).ListAttachments(target); } @@ -1588,45 +1207,24 @@ (level == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) || (level == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) || (level == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID)); - - result.clear(); + + FindRequest request(level); DicomTagConstraint c(tag, ConstraintType_Equal, value, true, true); - DatabaseDicomTagConstraints query; bool isIdentical; // unused - query.AddConstraint(c.ConvertToDatabaseConstraint(isIdentical, level, DicomTagType_Identifier)); - - - class Operations : public IReadOnlyOperations + request.GetDicomTagConstraints().AddConstraint(c.ConvertToDatabaseConstraint(isIdentical, level, DicomTagType_Identifier)); + + FindResponse response; + ExecuteFind(response, request); + + result.clear(); + result.reserve(response.GetSize()); + + for (size_t i = 0; i < response.GetSize(); i++) { - private: - std::vector<std::string>& result_; - const DatabaseDicomTagConstraints& query_; - ResourceType level_; - - public: - Operations(std::vector<std::string>& result, - const DatabaseDicomTagConstraints& query, - ResourceType level) : - result_(result), - query_(query), - level_(level) - { - } - - virtual void Apply(ReadOnlyTransaction& transaction) ORTHANC_OVERRIDE - { - // TODO - CANDIDATE FOR "TransactionType_Implicit" - std::list<std::string> tmp; - std::set<std::string> labels; - transaction.ApplyLookupResources(tmp, NULL, query_, level_, labels, LabelsConstraint_Any, 0); - CopyListToVector(result_, tmp); - } - }; - - Operations operations(result, query, level); - Apply(operations); + result.push_back(response.GetResourceByIndex(i).GetIdentifier()); + } } @@ -1683,139 +1281,116 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } - - class Operations : public ReadOnlyOperationsT5<bool&, DicomMap&, const std::string&, ResourceType, ResourceType> + FindRequest request(expectedType); + request.SetOrthancId(expectedType, publicId); + request.SetRetrieveMainDicomTags(true); + + FindResponse response; + ExecuteFind(response, request); + + if (response.GetSize() == 0) { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE + return false; + } + else if (response.GetSize() > 1) + { + throw OrthancException(ErrorCode_DatabasePlugin); + } + else + { + result.Clear(); + if (expectedType == ResourceType_Study) { - // Lookup for the requested resource - int64_t id; - ResourceType type; - if (!transaction.LookupResource(id, type, tuple.get<2>()) || - type != tuple.get<3>()) - { - tuple.get<0>() = false; - } - else if (type == ResourceType_Study) + DicomMap tmp; + response.GetResourceByIndex(0).GetMainDicomTags(tmp, expectedType); + + switch (levelOfInterest) { - DicomMap tmp; - transaction.GetMainDicomTags(tmp, id); - - switch (tuple.get<4>()) - { - case ResourceType_Patient: - tmp.ExtractPatientInformation(tuple.get<1>()); - tuple.get<0>() = true; - break; - - case ResourceType_Study: - tmp.ExtractStudyInformation(tuple.get<1>()); - tuple.get<0>() = true; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } + case ResourceType_Study: + tmp.ExtractStudyInformation(result); + break; + + case ResourceType_Patient: + tmp.ExtractPatientInformation(result); + break; + + default: + throw OrthancException(ErrorCode_InternalError); } - else - { - transaction.GetMainDicomTags(tuple.get<1>(), id); - tuple.get<0>() = true; - } } - }; - - result.Clear(); - - bool found; - Operations operations; - operations.Apply(*this, found, result, publicId, expectedType, levelOfInterest); - return found; + else + { + assert(expectedType == levelOfInterest); + response.GetResourceByIndex(0).GetMainDicomTags(result, expectedType); + } + return true; + } } bool StatelessDatabaseOperations::GetAllMainDicomTags(DicomMap& result, const std::string& instancePublicId) { - class Operations : public ReadOnlyOperationsT3<bool&, DicomMap&, const std::string&> - { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - // Lookup for the requested resource - int64_t instance; - ResourceType type; - if (!transaction.LookupResource(instance, type, tuple.get<2>()) || - type != ResourceType_Instance) - { - tuple.get<0>() = false; - } - else - { - DicomMap tmp; - - transaction.GetMainDicomTags(tmp, instance); - tuple.get<1>().Merge(tmp); - - int64_t series; - if (!transaction.LookupParent(series, instance)) - { - throw OrthancException(ErrorCode_InternalError); - } - - tmp.Clear(); - transaction.GetMainDicomTags(tmp, series); - tuple.get<1>().Merge(tmp); - - int64_t study; - if (!transaction.LookupParent(study, series)) - { - throw OrthancException(ErrorCode_InternalError); - } - - tmp.Clear(); - transaction.GetMainDicomTags(tmp, study); - tuple.get<1>().Merge(tmp); + FindRequest request(ResourceType_Instance); + request.SetOrthancId(ResourceType_Instance, instancePublicId); + request.GetParentSpecification(ResourceType_Study).SetRetrieveMainDicomTags(true); + request.GetParentSpecification(ResourceType_Series).SetRetrieveMainDicomTags(true); + request.SetRetrieveMainDicomTags(true); #ifndef NDEBUG - { - // Sanity test to check that all the main DICOM tags from the - // patient level are copied at the study level - - int64_t patient; - if (!transaction.LookupParent(patient, study)) - { - throw OrthancException(ErrorCode_InternalError); - } - - tmp.Clear(); - transaction.GetMainDicomTags(tmp, study); - - std::set<DicomTag> patientTags; - tmp.GetTags(patientTags); - - for (std::set<DicomTag>::const_iterator - it = patientTags.begin(); it != patientTags.end(); ++it) - { - assert(tuple.get<1>().HasTag(*it)); - } - } + // For sanity check below + request.GetParentSpecification(ResourceType_Patient).SetRetrieveMainDicomTags(true); #endif - - tuple.get<0>() = true; + + FindResponse response; + ExecuteFind(response, request); + + if (response.GetSize() == 0) + { + return false; + } + else if (response.GetSize() > 1) + { + throw OrthancException(ErrorCode_DatabasePlugin); + } + else + { + const FindResponse::Resource& resource = response.GetResourceByIndex(0); + + result.Clear(); + + DicomMap tmp; + resource.GetMainDicomTags(tmp, ResourceType_Instance); + result.Merge(tmp); + + tmp.Clear(); + resource.GetMainDicomTags(tmp, ResourceType_Series); + result.Merge(tmp); + + tmp.Clear(); + resource.GetMainDicomTags(tmp, ResourceType_Study); + result.Merge(tmp); + +#ifndef NDEBUG + { + // Sanity test to check that all the main DICOM tags from the + // patient level are copied at the study level + tmp.Clear(); + resource.GetMainDicomTags(tmp, ResourceType_Patient); + + std::set<DicomTag> patientTags; + tmp.GetTags(patientTags); + + for (std::set<DicomTag>::const_iterator + it = patientTags.begin(); it != patientTags.end(); ++it) + { + assert(result.HasTag(*it)); } } - }; - - result.Clear(); - - bool found; - Operations operations; - operations.Apply(*this, found, result, instancePublicId); - return found; +#endif + + return true; + } } @@ -1845,113 +1420,27 @@ const std::string& publicId, ResourceType parentType) { - class Operations : public ReadOnlyOperationsT4<bool&, std::string&, const std::string&, ResourceType> - { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - ResourceType type; - int64_t id; - if (!transaction.LookupResource(id, type, tuple.get<2>())) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - while (type != tuple.get<3>()) - { - int64_t parentId; - - if (type == ResourceType_Patient || // Cannot further go up in hierarchy - !transaction.LookupParent(parentId, id)) - { - tuple.get<0>() = false; - return; - } - - id = parentId; - type = GetParentResourceType(type); - } - - tuple.get<0>() = true; - tuple.get<1>() = transaction.GetPublicId(id); - } - }; - - bool found; - Operations operations; - operations.Apply(*this, found, target, publicId, parentType); - return found; - } - - - void StatelessDatabaseOperations::ApplyLookupResources(std::vector<std::string>& resourcesId, - std::vector<std::string>* instancesId, - const DatabaseLookup& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, - LabelsConstraint labelsConstraint, - uint32_t limit) - { - class Operations : public ReadOnlyOperationsT6<bool, const DatabaseDicomTagConstraints&, ResourceType, - const std::set<std::string>&, LabelsConstraint, size_t> + const ResourceType level = GetChildResourceType(parentType); + + FindRequest request(level); + request.SetOrthancId(level, publicId); + request.SetRetrieveParentIdentifier(true); + + FindResponse response; + ExecuteFind(response, request); + + if (response.GetSize() == 0) { - private: - std::list<std::string> resourcesList_; - std::list<std::string> instancesList_; - - public: - const std::list<std::string>& GetResourcesList() const - { - return resourcesList_; - } - - const std::list<std::string>& GetInstancesList() const - { - return instancesList_; - } - - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - // TODO - CANDIDATE FOR "TransactionType_Implicit" - if (tuple.get<0>()) - { - transaction.ApplyLookupResources( - resourcesList_, &instancesList_, tuple.get<1>(), tuple.get<2>(), tuple.get<3>(), tuple.get<4>(), tuple.get<5>()); - } - else - { - transaction.ApplyLookupResources( - resourcesList_, NULL, tuple.get<1>(), tuple.get<2>(), tuple.get<3>(), tuple.get<4>(), tuple.get<5>()); - } - } - }; - - if (!labels.empty() && - !db_.GetDatabaseCapabilities().HasLabelsSupport()) + return false; + } + else if (response.GetSize() > 1) { - throw OrthancException(ErrorCode_NotImplemented, "The database backend doesn't support labels"); - } - - for (std::set<std::string>::const_iterator it = labels.begin(); it != labels.end(); ++it) - { - ServerToolbox::CheckValidLabel(*it); + throw OrthancException(ErrorCode_DatabasePlugin); } - - DatabaseDicomTagConstraints normalized; - - assert(mainDicomTagsRegistry_.get() != NULL); - mainDicomTagsRegistry_->NormalizeLookup(normalized, lookup, queryLevel); - - Operations operations; - operations.Apply(*this, (instancesId != NULL), normalized, queryLevel, labels, labelsConstraint, limit); - - CopyListToVector(resourcesId, operations.GetResourcesList()); - - if (instancesId != NULL) - { - CopyListToVector(*instancesId, operations.GetInstancesList()); + else + { + target = response.GetResourceByIndex(0).GetParentIdentifier(); + return true; } } @@ -3596,28 +3085,12 @@ const std::string& publicId, ResourceType level) { - class Operations : public ReadOnlyOperationsT3<std::set<std::string>&, const std::string&, ResourceType> - { - public: - virtual void ApplyTuple(ReadOnlyTransaction& transaction, - const Tuple& tuple) ORTHANC_OVERRIDE - { - ResourceType type; - int64_t id; - if (!transaction.LookupResource(id, type, tuple.get<1>()) || - tuple.get<2>() != type) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else - { - transaction.ListLabels(tuple.get<0>(), id); - } - } - }; - - Operations operations; - operations.Apply(*this, target, publicId, level); + FindRequest request(level); + request.SetOrthancId(level, publicId); + request.SetRetrieveLabels(true); + + FindResponse response; + target = ExecuteSingleResource(response, request).GetLabels(); } @@ -3727,6 +3200,46 @@ return db_.GetDatabaseCapabilities().HasFindSupport(); } + void StatelessDatabaseOperations::ExecuteCount(uint64_t& count, + const FindRequest& request) + { + class IntegratedCount : public ReadOnlyOperationsT3<uint64_t&, const FindRequest&, + const IDatabaseWrapper::Capabilities&> + { + public: + virtual void ApplyTuple(ReadOnlyTransaction& transaction, + const Tuple& tuple) ORTHANC_OVERRIDE + { + transaction.ExecuteCount(tuple.get<0>(), tuple.get<1>(), tuple.get<2>()); + } + }; + + class Compatibility : public ReadOnlyOperationsT3<uint64_t&, const FindRequest&, const IDatabaseWrapper::Capabilities&> + { + public: + virtual void ApplyTuple(ReadOnlyTransaction& transaction, + const Tuple& tuple) ORTHANC_OVERRIDE + { + std::list<std::string> identifiers; + transaction.ExecuteFind(identifiers, tuple.get<2>(), tuple.get<1>()); + tuple.get<0>() = identifiers.size(); + } + }; + + IDatabaseWrapper::Capabilities capabilities = db_.GetDatabaseCapabilities(); + + if (db_.HasIntegratedFind()) + { + IntegratedCount operations; + operations.Apply(*this, count, request, capabilities); + } + else + { + Compatibility operations; + operations.Apply(*this, count, request, capabilities); + } + } + void StatelessDatabaseOperations::ExecuteFind(FindResponse& response, const FindRequest& request) { @@ -3781,15 +3294,25 @@ **/ std::list<std::string> identifiers; - FindStage find; - find.Apply(*this, identifiers, capabilities, request); + std::string publicId; + if (request.IsTrivialFind(publicId)) + { + // This is a trivial case for which no transaction is needed + identifiers.push_back(publicId); + } + else + { + // Non-trival case, a transaction is needed + FindStage find; + find.Apply(*this, identifiers, capabilities, request); + } ExpandStage expand; for (std::list<std::string>::const_iterator it = identifiers.begin(); it != identifiers.end(); ++it) { /** - * Not that the resource might have been deleted (as we are in + * Note that the resource might have been deleted (as we are in * another transaction). The database engine must ignore such * error cases. **/
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -39,102 +39,6 @@ class ParsedDicomFile; struct ServerIndexChange; - class ExpandedResource : public boost::noncopyable - { - private: - std::string id_; - ResourceType level_; - DicomMap tags_; // all main tags and main sequences from DB - - public: - std::string mainDicomTagsSignature_; - std::string parentId_; - std::list<std::string> childrenIds_; - std::map<MetadataType, std::string> metadata_; - std::string anonymizedFrom_; - std::string modifiedFrom_; - std::string lastUpdate_; - std::set<DicomTag> missingRequestedTags_; - - // for patients/studies/series - bool isStable_; - - // for series only - int expectedNumberOfInstances_; - std::string status_; - - // for instances only - size_t fileSize_; - std::string fileUuid_; - int indexInSeries_; - - // New in Orthanc 1.12.0 - std::set<std::string> labels_; - - public: - // TODO - Cleanup - ExpandedResource() : - level_(ResourceType_Instance), - isStable_(false), - expectedNumberOfInstances_(0), - fileSize_(0), - indexInSeries_(0) - { - } - - void SetResource(ResourceType level, - const std::string& id) - { - level_ = level; - id_ = id; - } - - const std::string& GetPublicId() const - { - return id_; - } - - ResourceType GetLevel() const - { - return level_; - } - - DicomMap& GetMainDicomTags() - { - return tags_; - } - - const DicomMap& GetMainDicomTags() const - { - return tags_; - } - }; - - enum ExpandResourceFlags - { - ExpandResourceFlags_None = 0, - // used to fetch from DB and for output - ExpandResourceFlags_IncludeMetadata = (1 << 0), - ExpandResourceFlags_IncludeChildren = (1 << 1), - ExpandResourceFlags_IncludeMainDicomTags = (1 << 2), - ExpandResourceFlags_IncludeLabels = (1 << 3), - - // only used for output - ExpandResourceFlags_IncludeAllMetadata = (1 << 4), // new in Orthanc 1.12.4 - ExpandResourceFlags_IncludeIsStable = (1 << 5), // new in Orthanc 1.12.4 - - ExpandResourceFlags_DefaultExtract = (ExpandResourceFlags_IncludeMetadata | - ExpandResourceFlags_IncludeChildren | - ExpandResourceFlags_IncludeMainDicomTags | - ExpandResourceFlags_IncludeLabels), - - ExpandResourceFlags_DefaultOutput = (ExpandResourceFlags_IncludeMetadata | - ExpandResourceFlags_IncludeChildren | - ExpandResourceFlags_IncludeMainDicomTags | - ExpandResourceFlags_IncludeLabels | - ExpandResourceFlags_IncludeIsStable) - }; - class StatelessDatabaseOperations : public boost::noncopyable { public: @@ -219,38 +123,12 @@ * Read-only methods from "IDatabaseWrapper" **/ - void ApplyLookupResources(std::list<std::string>& resourcesId, - std::list<std::string>* instancesId, // Can be NULL if not needed - const DatabaseDicomTagConstraints& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, // New in Orthanc 1.12.0 - LabelsConstraint labelsConstraint, // New in Orthanc 1.12.0 - uint32_t limit) - { - return transaction_.ApplyLookupResources(resourcesId, instancesId, lookup, queryLevel, - labels, labelsConstraint, limit); - } - void GetAllMetadata(std::map<MetadataType, std::string>& target, int64_t id) { transaction_.GetAllMetadata(target, id); } - void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType) - { - return transaction_.GetAllPublicIds(target, resourceType); - } - - void GetAllPublicIds(std::list<std::string>& target, - ResourceType resourceType, - size_t since, - uint32_t limit) - { - return transaction_.GetAllPublicIds(target, resourceType, since, limit); - } - void GetChanges(std::list<ServerIndexChange>& target /*out*/, bool& done /*out*/, int64_t since, @@ -275,12 +153,6 @@ transaction_.GetChildrenInternalId(target, id); } - void GetChildrenPublicId(std::list<std::string>& target, - int64_t id) - { - transaction_.GetChildrenPublicId(target, id); - } - void GetExportedResources(std::list<ExportedResource>& target /*out*/, bool& done /*out*/, int64_t since, @@ -381,20 +253,6 @@ { return transaction_.LookupResource(id, type, publicId); } - - bool LookupResourceAndParent(int64_t& id, - ResourceType& type, - std::string& parentPublicId, - const std::string& publicId) - { - return transaction_.LookupResourceAndParent(id, type, parentPublicId, publicId); - } - - void ListLabels(std::set<std::string>& target, - int64_t id) - { - transaction_.ListLabels(target, id); - } void ListAllLabels(std::set<std::string>& target) { @@ -407,6 +265,13 @@ bool HasReachedMaxPatientCount(unsigned int maximumPatientCount, const std::string& patientId); + void ExecuteCount(uint64_t& count, + const FindRequest& request, + const IDatabaseWrapper::Capabilities& capabilities) + { + transaction_.ExecuteCount(count, request, capabilities); + } + void ExecuteFind(FindResponse& response, const FindRequest& request, const IDatabaseWrapper::Capabilities& capabilities) @@ -603,6 +468,9 @@ void ApplyInternal(IReadOnlyOperations* readOperations, IReadWriteOperations* writeOperations); + const FindResponse::Resource &ExecuteSingleResource(FindResponse &response, + const FindRequest &request); + protected: void StandaloneRecycling(MaxStorageMode maximumStorageMode, uint64_t maximumStorageSize, @@ -641,12 +509,6 @@ void Apply(IReadWriteOperations& operations); - bool ExpandResource(ExpandedResource& target, - const std::string& publicId, - ResourceType level, - const std::set<DicomTag>& requestedTags, - ExpandResourceFlags expandFlags); - void GetAllMetadata(std::map<MetadataType, std::string>& target, const std::string& publicId, ResourceType level); @@ -654,11 +516,6 @@ void GetAllUuids(std::list<std::string>& target, ResourceType resourceType); - void GetAllUuids(std::list<std::string>& target, - ResourceType resourceType, - size_t since, - uint32_t limit); - void GetGlobalStatistics(/* out */ uint64_t& diskSize, /* out */ uint64_t& uncompressedSize, /* out */ uint64_t& countPatients, @@ -668,7 +525,8 @@ bool LookupAttachment(FileInfo& attachment, int64_t& revision, - const std::string& instancePublicId, + ResourceType level, + const std::string& publicId, FileContentType contentType); void GetChanges(Json::Value& target, @@ -696,12 +554,23 @@ bool IsProtectedPatient(const std::string& publicId); void GetChildren(std::list<std::string>& result, + ResourceType level, const std::string& publicId); + // Always prefer this flavor, which is more efficient than the flavor without "level" + void GetChildInstances(std::list<std::string>& result, + const std::string& publicId, + ResourceType level); + void GetChildInstances(std::list<std::string>& result, const std::string& publicId); bool LookupMetadata(std::string& target, + const std::string& publicId, + ResourceType expectedType, + MetadataType type); + + bool LookupMetadata(std::string& target, int64_t& revision, const std::string& publicId, ResourceType expectedType, @@ -742,7 +611,7 @@ ResourceType expectedType, ResourceType levelOfInterest); - // Only applicable at the instance level + // Only applicable at the instance level, retrieves tags from patient/study/series levels bool GetAllMainDicomTags(DicomMap& result, const std::string& instancePublicId); @@ -753,14 +622,6 @@ const std::string& publicId, ResourceType parentType); - void ApplyLookupResources(std::vector<std::string>& resourcesId, - std::vector<std::string>* instancesId, // Can be NULL if not needed - const DatabaseLookup& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, - LabelsConstraint labelsConstraint, - uint32_t limit); - bool DeleteResource(Json::Value& remainingAncestor /* out */, const std::string& uuid, ResourceType expectedType); @@ -860,5 +721,8 @@ void ExecuteFind(FindResponse& response, const FindRequest& request); + + void ExecuteCount(uint64_t& count, + const FindRequest& request); }; }
--- a/OrthancServer/Sources/Database/Upgrade3To4.sql Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Upgrade3To4.sql Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ -- 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 +-- Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +-- Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/Upgrade4To5.sql Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/Upgrade4To5.sql Thu Jan 30 17:41:33 2025 +0100 @@ -2,8 +2,8 @@ -- 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 +-- Copyright (C) 2024-2025 Orthanc Team SRL, Belgium +-- Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/VoidDatabaseListener.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/VoidDatabaseListener.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Database/VoidDatabaseListener.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Database/VoidDatabaseListener.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/DicomInstanceOrigin.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/DicomInstanceOrigin.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/DicomInstanceOrigin.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/DicomInstanceOrigin.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/DicomInstanceToStore.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/DicomInstanceToStore.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/DicomInstanceToStore.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/DicomInstanceToStore.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/EmbeddedResourceHttpHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/EmbeddedResourceHttpHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/EmbeddedResourceHttpHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/EmbeddedResourceHttpHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ExportedResource.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ExportedResource.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ExportedResource.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ExportedResource.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/IDicomImageDecoder.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/IDicomImageDecoder.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/IServerListener.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/IServerListener.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/JobEvent.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/JobEvent.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/LuaScripting.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/LuaScripting.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/LuaScripting.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/LuaScripting.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancConfiguration.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancConfiguration.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -1169,6 +1169,14 @@ { warning = Warnings_005_RequestingTagFromLowerResourceLevel; } + else if (name == "W006_RequestingTagFromMetaHeader") + { + warning = Warnings_006_RequestingTagFromMetaHeader; + } + else if (name == "W007_MissingRequestedTagsNotReadFromDisk") + { + warning = Warnings_007_MissingRequestedTagsNotReadFromDisk; + } else { throw OrthancException(ErrorCode_BadFileFormat, name + " is not recognized as a valid warning name");
--- a/OrthancServer/Sources/OrthancConfiguration.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancConfiguration.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancFindRequestHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancFindRequestHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -30,7 +30,7 @@ #include "../../OrthancFramework/Sources/Lua/LuaFunctionCall.h" #include "../../OrthancFramework/Sources/MetricsRegistry.h" #include "OrthancConfiguration.h" -#include "ResourceFinder.cpp" +#include "ResourceFinder.h" #include "Search/DatabaseLookup.h" #include "ServerContext.h" #include "ServerToolbox.h" @@ -82,102 +82,6 @@ } - static void AddAnswer(DicomFindAnswers& answers, - ServerContext& context, - const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson, - ResourceType level, - const DicomArray& query, - const std::list<DicomTag>& sequencesToReturn, - const std::string& defaultPrivateCreator, - const std::map<uint16_t, std::string>& privateCreators, - const std::string& retrieveAet, - bool allowStorageAccess) - { - ExpandedResource resource; - std::set<DicomTag> requestedTags; - - query.GetTags(requestedTags); - requestedTags.erase(DICOM_TAG_QUERY_RETRIEVE_LEVEL); // this is not part of the answer - - // reuse ExpandResource to get missing tags and computed tags (ModalitiesInStudy ...). This code is therefore shared between C-Find, tools/find, list-resources and QIDO-RS - context.ExpandResource(resource, publicId, mainDicomTags, instanceId, dicomAsJson, - level, requestedTags, ExpandResourceFlags_IncludeMainDicomTags, allowStorageAccess); - - DicomMap result; - - /** - * Add the mandatory "Retrieve AE Title (0008,0054)" tag, which was missing in Orthanc <= 1.7.2. - * http://dicom.nema.org/medical/dicom/current/output/html/part04.html#sect_C.4.1.1.3.2 - * https://groups.google.com/g/orthanc-users/c/-7zNTKR_PMU/m/kfjwzEVNAgAJ - **/ - result.SetValue(DICOM_TAG_RETRIEVE_AE_TITLE, retrieveAet, false /* not binary */); - - for (size_t i = 0; i < query.GetSize(); i++) - { - if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL) - { - // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052)) - result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue()); - } - else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - // Do not include the encoding, this is handled by class ParsedDicomFile - } - else - { - const DicomTag& tag = query.GetElement(i).GetTag(); - const DicomValue* value = resource.GetMainDicomTags().TestAndGetValue(tag); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - result.SetValue(tag, value->GetContent(), false); - } - else - { - result.SetValue(tag, "", false); - } - } - } - - if (result.GetSize() == 0 && - sequencesToReturn.empty()) - { - CLOG(WARNING, DICOM) << "The C-FIND request does not return any DICOM tag"; - } - else if (sequencesToReturn.empty()) - { - answers.Add(result); - } - else if (dicomAsJson == NULL) - { - CLOG(WARNING, DICOM) << "C-FIND query requesting a sequence, but reading JSON from disk is disabled"; - answers.Add(result); - } - else - { - ParsedDicomFile dicom(result, GetDefaultDicomEncoding(), - true /* be permissive, cf. issue #136 */, defaultPrivateCreator, privateCreators); - - for (std::list<DicomTag>::const_iterator tag = sequencesToReturn.begin(); - tag != sequencesToReturn.end(); ++tag) - { - assert(dicomAsJson != NULL); - const Json::Value& source = (*dicomAsJson) [tag->Format()]; - - CopySequence(dicom, *tag, source, defaultPrivateCreator, privateCreators); - } - - answers.Add(dicom); - } - } - - - bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */, ResourceType level, const DicomTag& tag, @@ -248,88 +152,6 @@ } - class OrthancFindRequestHandler::LookupVisitor : public ServerContext::ILookupVisitor - { - private: - DicomFindAnswers& answers_; - ServerContext& context_; - ResourceType level_; - const DicomMap& query_; - DicomArray queryAsArray_; - const std::list<DicomTag>& sequencesToReturn_; - std::string defaultPrivateCreator_; // the private creator to use if the group is not defined in the query itself - const std::map<uint16_t, std::string>& privateCreators_; // the private creators defined in the query itself - std::string retrieveAet_; - FindStorageAccessMode findStorageAccessMode_; - - public: - LookupVisitor(DicomFindAnswers& answers, - ServerContext& context, - ResourceType level, - const DicomMap& query, - const std::list<DicomTag>& sequencesToReturn, - const std::map<uint16_t, std::string>& privateCreators, - FindStorageAccessMode findStorageAccessMode) : - answers_(answers), - context_(context), - level_(level), - query_(query), - queryAsArray_(query), - sequencesToReturn_(sequencesToReturn), - privateCreators_(privateCreators), - findStorageAccessMode_(findStorageAccessMode) - { - answers_.SetComplete(false); - - { - OrthancConfiguration::ReaderLock lock; - defaultPrivateCreator_ = lock.GetConfiguration().GetDefaultPrivateCreator(); - retrieveAet_ = lock.GetConfiguration().GetOrthancAET(); - } - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - // Ask the "DICOM-as-JSON" attachment only if sequences are to - // be returned OR if "query_" contains non-main DICOM tags! - - DicomMap withoutSpecialTags; - withoutSpecialTags.Assign(query_); - - // Check out "ComputeCounters()" - withoutSpecialTags.Remove(DICOM_TAG_MODALITIES_IN_STUDY); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES); - withoutSpecialTags.Remove(DICOM_TAG_SOP_CLASSES_IN_STUDY); - - // Check out "AddAnswer()" - withoutSpecialTags.Remove(DICOM_TAG_SPECIFIC_CHARACTER_SET); - withoutSpecialTags.Remove(DICOM_TAG_QUERY_RETRIEVE_LEVEL); - - return (!sequencesToReturn_.empty() || - !withoutSpecialTags.HasOnlyMainDicomTags()); - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - answers_.SetComplete(true); - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson) ORTHANC_OVERRIDE - { - AddAnswer(answers_, context_, publicId, instanceId, mainDicomTags, dicomAsJson, level_, queryAsArray_, sequencesToReturn_, - defaultPrivateCreator_, privateCreators_, retrieveAet_, IsStorageAccessAllowedForAnswers(findStorageAccessMode_)); - } - }; - - namespace { class LookupVisitorV2 : public ResourceFinder::IVisitor @@ -622,31 +444,12 @@ * Run the query. **/ - size_t limit = (level == ResourceType_Instance) ? maxInstances_ : maxResults_; - - - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(level, ResponseContentFlags_ID); - finder.SetDatabaseLookup(lookup); - finder.AddRequestedTags(requestedTags); + ResourceFinder finder(level, ResponseContentFlags_ID, context_.GetFindStorageAccessMode(), context_.GetIndex().HasFindSupport()); + finder.SetDatabaseLookup(lookup); + finder.AddRequestedTags(requestedTags); - LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators); - finder.Execute(visitor, context_); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - - LookupVisitor visitor(answers, context_, level, *filteredInput, sequencesToReturn, privateCreators, context_.GetFindStorageAccessMode()); - context_.Apply(visitor, lookup, level, 0 /* "since" is not relevant to C-FIND */, limit); - } + LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators); + finder.Execute(visitor, context_); }
--- a/OrthancServer/Sources/OrthancFindRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancFindRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancGetRequestHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancGetRequestHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -165,6 +165,7 @@ * 2. Select the preferred transfer syntaxes, which corresponds to * the source transfer syntax, plus all the uncompressed transfer * syntaxes if transcoding is enabled. + * This way, we minimize the transcoding on our side. **/ std::list<DicomTransferSyntax> preferred; @@ -208,7 +209,16 @@ } } - // No preferred syntax was accepted + // No preferred syntax was accepted but, if a PC has been accepted, it means that we have accepted a TS. + // This maybe means that we need to transcode twice on our side (from a compressed format to another compressed format). + if (allowTranscoding && accepted.size() > 0) + { + Accepted::const_iterator it = accepted.begin(); + selectedPresentationId = it->second; + selectedSyntax = it->first; + return true; + } + return false; }
--- a/OrthancServer/Sources/OrthancGetRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancGetRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancHttpHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancHttpHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancHttpHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancHttpHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancInitialization.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancInitialization.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancInitialization.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancInitialization.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancMoveRequestHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancMoveRequestHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancMoveRequestHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancMoveRequestHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -807,7 +807,7 @@ { // Retrieve all the instances of the parent resource std::list<std::string> siblingInstances; - context.GetIndex().GetChildInstances(siblingInstances, parent); + context.GetIndex().GetChildInstances(siblingInstances, parent, parentType); if (siblingInstances.empty()) {
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -501,11 +501,15 @@ static const std::string GET_SHORT = "short"; static const std::string GET_REQUESTED_TAGS_OLD = "requestedTags"; // This was the only option in Orthanc <= 1.12.3 static const std::string GET_REQUESTED_TAGS = "requested-tags"; + static const std::string GET_RESPONSE_CONTENT = "response-content"; + static const std::string GET_EXPAND = "expand"; static const std::string POST_SIMPLIFY = "Simplify"; static const std::string POST_FULL = "Full"; static const std::string POST_SHORT = "Short"; static const std::string POST_REQUESTED_TAGS = "RequestedTags"; + static const std::string POST_RESPONSE_CONTENT = "ResponseContent"; + static const std::string POST_EXPAND = "Expand"; static const std::string DOCUMENT_SIMPLIFY = "report the DICOM tags in human-readable format (using the symbolic name of the tags)"; @@ -634,19 +638,100 @@ } catch (OrthancException& ex) { - throw OrthancException(ErrorCode_BadRequest, std::string("Invalid requestedTags argument: ") + ex.What() + " " + ex.GetDetails()); + throw OrthancException(ErrorCode_BadRequest, std::string("Invalid requested-tags argument: ") + ex.What() + " " + ex.GetDetails()); } } } - void OrthancRestApi::DocumentRequestedTags(RestApiGetCall& call) + void OrthancRestApi::DocumentRequestedTags(RestApiCall& call) { + if (call.GetMethod() == HttpMethod_Get) + { call.GetDocumentation().SetHttpGetArgument(GET_REQUESTED_TAGS, RestApiCallDocumentation::Type_String, "If present, list the DICOM Tags you want to list in the response. This argument is a semi-column separated list " "of DICOM Tags identifiers; e.g: '" + GET_REQUESTED_TAGS + "=0010,0010;PatientBirthDate'. " "The tags requested tags are returned in the 'RequestedTags' field in the response. " "Note that, if you are requesting tags that are not listed in the Main Dicom Tags stored in DB, building the response " - "might be slow since Orthanc will need to access the DICOM files. If not specified, Orthanc will return ", false); + "might be slow since Orthanc will need to access the DICOM files. If not specified, Orthanc will return " + "all Main Dicom Tags to keep backward compatibility with Orthanc prior to 1.11.0.", false); + } + else if (call.GetMethod() == HttpMethod_Post) + { + call.GetDocumentation().SetRequestField(POST_REQUESTED_TAGS, RestApiCallDocumentation::Type_JsonListOfStrings, + "A list of DICOM tags to include in the response (applicable only if \"Expand\" is set to true). " + "The tags requested tags are returned in the 'RequestedTags' field in the response. " + "Note that, if you are requesting tags that are not listed in the Main Dicom Tags stored in DB, building the response " + "might be slow since Orthanc will need to access the DICOM files. If not specified, Orthanc will return " + "all Main Dicom Tags to keep backward compatibility with Orthanc prior to 1.11.0.", false); + } + else + { + throw OrthancException(ErrorCode_InternalError); + } } + void OrthancRestApi::GetResponseContentAndExpand(ResponseContentFlags& responseContent, + const RestApiGetCall& call) + { + if (call.HasArgument(GET_RESPONSE_CONTENT)) + { + std::string s = call.GetArgument(GET_RESPONSE_CONTENT, ""); + responseContent = ResponseContentFlags_Default; + + if (!s.empty()) + { + std::set<std::string> splitResponseContent; + Toolbox::SplitString(splitResponseContent, s, ';'); + + for (std::set<std::string>::const_iterator it = splitResponseContent.begin(); it != splitResponseContent.end(); ++it) + { + responseContent = static_cast<ResponseContentFlags>(static_cast<uint32_t>(responseContent) | StringToResponseContent(*it)); + } + } + } + else if (call.HasArgument(GET_EXPAND) && call.GetBooleanArgument("expand", true)) + { + responseContent = ResponseContentFlags_ExpandTrue; + } + else + { + responseContent = ResponseContentFlags_ID; + } + } + + void OrthancRestApi::DocumentResponseContentAndExpand(RestApiCall& call) + { + if (call.GetMethod() == HttpMethod_Get) + { + call.GetDocumentation().SetHttpGetArgument(GET_RESPONSE_CONTENT, RestApiCallDocumentation::Type_String, + "Defines the content of response for each returned resource. Allowed values are `MainDicomTags`, " + "`Metadata`, `Children`, `Parent`, `Labels`, `Status`, `IsStable`, `Attachments`. If not specified, Orthanc " + "will return `MainDicomTags`, `Metadata`, `Children`, `Parent`, `Labels`, `Status`, `IsStable`." + "e.g: '" + GET_RESPONSE_CONTENT + "=MainDicomTags;Children " + "(new in Orthanc 1.12.5 - overrides `expand`)", false); + + call.GetDocumentation().SetHttpGetArgument(GET_EXPAND, RestApiCallDocumentation::Type_String, + "If present, retrieve detailed information about the individual resources, not only their Orthanc identifiers", false); + + } + else if (call.GetMethod() == HttpMethod_Post) + { + call.GetDocumentation().SetRequestField(POST_RESPONSE_CONTENT, RestApiCallDocumentation::Type_JsonListOfStrings, + "Defines the content of response for each returned resource. (this field, if present, overrides the \"Expand\" field). " + "Allowed values are `MainDicomTags`, " + "`Metadata`, `Children`, `Parent`, `Labels`, `Status`, `IsStable`, `Attachments`. If not specified, Orthanc " + "will return `MainDicomTags`, `Metadata`, `Children`, `Parent`, `Labels`, `Status`, `IsStable`." + "(new in Orthanc 1.12.5)", false); + + call.GetDocumentation().SetRequestField(POST_EXPAND, RestApiCallDocumentation::Type_Boolean, + "If set to \"true\", retrieve detailed information about the individual resources, not only their Orthanc identifiers", false); + } + else + { + throw OrthancException(ErrorCode_InternalError); + } + + } + + }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -157,6 +157,11 @@ static void GetRequestedTags(std::set<DicomTag>& requestedTags, const RestApiGetCall& call); - static void DocumentRequestedTags(RestApiGetCall& call); + static void DocumentRequestedTags(RestApiCall& call); + + static void GetResponseContentAndExpand(ResponseContentFlags& responseContent, + const RestApiGetCall& call); + + static void DocumentResponseContentAndExpand(RestApiCall& call); }; }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestChanges.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestChanges.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -73,7 +73,7 @@ .SetHttpGetArgument("limit", RestApiCallDocumentation::Type_Number, "Limit the number of results", false) .SetHttpGetArgument("since", RestApiCallDocumentation::Type_Number, "Show only the resources since the provided index excluded", false) .SetHttpGetArgument("to", RestApiCallDocumentation::Type_Number, "Show only the resources till the provided index included (only available if your DB backend supports ExtendedChanges)", false) - .SetHttpGetArgument("type", RestApiCallDocumentation::Type_String, "Show only the changes of the provided type (only available if your DB backend supports ExtendedChanges)", false) + .SetHttpGetArgument("type", RestApiCallDocumentation::Type_String, "Show only the changes of the provided type (only available if your DB backend supports ExtendedChanges). Multiple values can be provided and must be separated by a ';'.", false) .AddAnswerType(MimeType_Json, "The list of changes") .SetAnswerField("Changes", RestApiCallDocumentation::Type_JsonListOfObjects, "The individual changes") .SetAnswerField("Done", RestApiCallDocumentation::Type_Boolean,
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -36,6 +36,7 @@ #include "../ServerContext.h" #include "../ServerJobs/DicomModalityStoreJob.h" #include "../ServerJobs/DicomMoveScuJob.h" +#include "../ServerJobs/DicomGetScuJob.h" #include "../ServerJobs/OrthancPeerStoreJob.h" #include "../ServerToolbox.h" #include "../StorageCommitmentReports.h" @@ -56,6 +57,7 @@ static const char* const KEY_CHECK_FIND = "CheckFind"; static const char* const SOP_CLASS_UID = "SOPClassUID"; static const char* const SOP_INSTANCE_UID = "SOPInstanceUID"; + static const char* const KEY_RETRIEVE_METHOD = "RetrieveMethod"; static RemoteModalityParameters MyGetModalityUsingSymbolicName(const std::string& name) { @@ -155,24 +157,31 @@ const DicomAssociationParameters& parameters, const Json::Value& body) { - DicomControlUserConnection connection(parameters); - + bool checkFind = false; + + if (body.type() == Json::objectValue && + body.isMember(KEY_CHECK_FIND)) + { + checkFind = SerializationToolbox::ReadBoolean(body, KEY_CHECK_FIND); + } + else + { + OrthancConfiguration::ReaderLock lock; + checkFind = lock.GetConfiguration().GetBooleanParameter("DicomEchoChecksFind", false); + } + + ScuOperationFlags operations = ScuOperationFlags_Echo; + + if (checkFind) + { + operations = static_cast<ScuOperationFlags>(operations | ScuOperationFlags_Find); + } + + DicomControlUserConnection connection(parameters, operations); if (connection.Echo()) { - bool find = false; - - if (body.type() == Json::objectValue && - body.isMember(KEY_CHECK_FIND)) - { - find = SerializationToolbox::ReadBoolean(body, KEY_CHECK_FIND); - } - else - { - OrthancConfiguration::ReaderLock lock; - find = lock.GetConfiguration().GetBooleanParameter("DicomEchoChecksFind", false); - } - - if (find) + + if (checkFind) { // Issue a C-FIND request at the study level about a random Study Instance UID const std::string studyInstanceUid = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study); @@ -385,7 +394,7 @@ DicomFindAnswers answers(false); { - DicomControlUserConnection connection(GetAssociationParameters(call)); + DicomControlUserConnection connection(GetAssociationParameters(call), ScuOperationFlags_FindPatient); FindPatient(answers, connection, fields); } @@ -428,7 +437,7 @@ DicomFindAnswers answers(false); { - DicomControlUserConnection connection(GetAssociationParameters(call)); + DicomControlUserConnection connection(GetAssociationParameters(call), ScuOperationFlags_FindStudy); FindStudy(answers, connection, fields); } @@ -472,7 +481,7 @@ DicomFindAnswers answers(false); { - DicomControlUserConnection connection(GetAssociationParameters(call)); + DicomControlUserConnection connection(GetAssociationParameters(call), ScuOperationFlags_FindStudy); FindSeries(answers, connection, fields); } @@ -517,7 +526,7 @@ DicomFindAnswers answers(false); { - DicomControlUserConnection connection(GetAssociationParameters(call)); + DicomControlUserConnection connection(GetAssociationParameters(call), ScuOperationFlags_FindStudy); FindInstance(answers, connection, fields); } @@ -566,7 +575,7 @@ return; } - DicomControlUserConnection connection(GetAssociationParameters(call)); + DicomControlUserConnection connection(GetAssociationParameters(call), ScuOperationFlags_Find); DicomFindAnswers patients(false); FindPatient(patients, connection, m); @@ -914,12 +923,25 @@ std::string targetAet; int timeout = -1; - + + QueryAccessor query(call); + + RetrieveMethod retrieveMethod = query.GetHandler().GetRemoteModality().GetRetrieveMethod(); + Json::Value body; if (call.ParseJsonRequest(body)) { + OrthancConfiguration::ReaderLock lock; + targetAet = Toolbox::GetJsonStringField(body, KEY_TARGET_AET, context.GetDefaultLocalApplicationEntityTitle()); timeout = Toolbox::GetJsonIntegerField(body, KEY_TIMEOUT, -1); + + std::string strRetrieveMethod = SerializationToolbox::ReadString(body, KEY_RETRIEVE_METHOD, ""); + + if (!strRetrieveMethod.empty()) + { + retrieveMethod = StringToRetrieveMethod(strRetrieveMethod); + } } else { @@ -934,45 +956,67 @@ } } - std::unique_ptr<DicomMoveScuJob> job(new DicomMoveScuJob(context)); - job->SetQueryFormat(OrthancRestApi::GetDicomFormat(body, DicomToJsonFormat_Short)); - + if (retrieveMethod == RetrieveMethod_SystemDefault) + { + retrieveMethod = context.GetDefaultDicomRetrieveMethod(); + } + + std::unique_ptr<DicomRetrieveScuBaseJob> job; + + + switch (retrieveMethod) { - QueryAccessor query(call); - job->SetTargetAet(targetAet); - job->SetLocalAet(query.GetHandler().GetLocalAet()); - job->SetRemoteModality(query.GetHandler().GetRemoteModality()); - - if (timeout >= 0) + case RetrieveMethod_Move: { - // New in Orthanc 1.7.0 - job->SetTimeout(static_cast<uint32_t>(timeout)); - } - else if (query.GetHandler().HasTimeout()) + job.reset(new DicomMoveScuJob(context)); + (dynamic_cast<DicomMoveScuJob*>(job.get()))->SetTargetAet(targetAet); + + LOG(WARNING) << "Driving C-Move SCU on remote modality " + << query.GetHandler().GetRemoteModality().GetApplicationEntityTitle() + << " to target modality " << targetAet; + }; break; + case RetrieveMethod_Get: { - // New in Orthanc 1.9.1 - job->SetTimeout(query.GetHandler().GetTimeout()); - } - - LOG(WARNING) << "Driving C-Move SCU on remote modality " - << query.GetHandler().GetRemoteModality().GetApplicationEntityTitle() - << " to target modality " << targetAet; - - if (allAnswers) + job.reset(new DicomGetScuJob(context)); + + LOG(WARNING) << "Driving C-Get SCU on remote modality " + << query.GetHandler().GetRemoteModality().GetApplicationEntityTitle(); + }; break; + default: + throw OrthancException(ErrorCode_NotImplemented); + } + + job->SetQueryFormat(OrthancRestApi::GetDicomFormat(body, DicomToJsonFormat_Short)); + + job->SetLocalAet(query.GetHandler().GetLocalAet()); + job->SetRemoteModality(query.GetHandler().GetRemoteModality()); + + if (timeout >= 0) + { + // New in Orthanc 1.7.0 + job->SetTimeout(static_cast<uint32_t>(timeout)); + } + else if (query.GetHandler().HasTimeout()) + { + // New in Orthanc 1.9.1 + job->SetTimeout(query.GetHandler().GetTimeout()); + } + + if (allAnswers) + { + for (size_t i = 0; i < query.GetHandler().GetAnswersCount(); i++) { - for (size_t i = 0; i < query.GetHandler().GetAnswersCount(); i++) - { - job->AddFindAnswer(query.GetHandler(), i); - } + job->AddFindAnswer(query.GetHandler(), i); } - else - { - job->AddFindAnswer(query.GetHandler(), index); - } + } + else + { + job->AddFindAnswer(query.GetHandler(), index); } OrthancRestApi::GetApi(call).SubmitCommandsJob (call, job.release(), true /* synchronous by default */, body); + } @@ -989,6 +1033,10 @@ "`DicomAet` configuration option.", false) .SetRequestField(KEY_TIMEOUT, RestApiCallDocumentation::Type_Number, "Timeout for the C-MOVE command, in seconds", false) + .SetRequestField(KEY_RETRIEVE_METHOD, RestApiCallDocumentation::Type_String, + "Force usage of C-MOVE or C-GET to retrieve the resource. If note defined in the payload, " + "the retrieve method is defined in the DicomDefaultRetrieveMethod configuration or in " + "DicomModalities->..->RetrieveMethod", false) .AddRequestType(MimeType_PlainText, "AET of the target modality"); } @@ -999,8 +1047,8 @@ { DocumentRetrieveShared(call); call.GetDocumentation() - .SetSummary("Retrieve one answer") - .SetDescription("Start a C-MOVE SCU command as a job, in order to retrieve one answer associated with the " + .SetSummary("Retrieve one answer with a C-MOVE or a C-GET SCU") + .SetDescription("Start a C-MOVE or a C-GET SCU command as a job, in order to retrieve one answer associated with the " "query/retrieve operation whose identifiers are provided in the URL: " "https://orthanc.uclouvain.be/book/users/rest.html#performing-retrieve-c-move") .SetUriArgument("index", "Index of the answer"); @@ -1012,13 +1060,15 @@ } + + static void RetrieveAllAnswers(RestApiPostCall& call) { if (call.IsDocumentation()) { DocumentRetrieveShared(call); call.GetDocumentation() - .SetSummary("Retrieve all answers") + .SetSummary("Retrieve all answers with C-MOVE SCU") .SetDescription("Start a C-MOVE SCU command as a job, in order to retrieve all the answers associated with the " "query/retrieve operation whose identifier is provided in the URL: " "https://orthanc.uclouvain.be/book/users/rest.html#performing-retrieve-c-move"); @@ -1536,6 +1586,48 @@ call.GetOutput().AnswerJson(answer); } + void ParseMoveGetJob(DicomRetrieveScuBaseJob& job, Json::Value& request, RestApiPostCall& call) + { + const ServerContext& context = OrthancRestApi::GetContext(call); + + if (!call.ParseJsonRequest(request) || + request.type() != Json::objectValue || + !request.isMember(KEY_RESOURCES) || + !request.isMember(KEY_LEVEL) || + request[KEY_RESOURCES].type() != Json::arrayValue || + request[KEY_LEVEL].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON body containing fields " + + std::string(KEY_RESOURCES) + " and " + std::string(KEY_LEVEL)); + } + + ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); + + std::string localAet = Toolbox::GetJsonStringField + (request, KEY_LOCAL_AET, context.GetDefaultLocalApplicationEntityTitle()); + + const RemoteModalityParameters source = + MyGetModalityUsingSymbolicName(call.GetUriComponent("id", "")); + + job.SetQueryFormat(DicomToJsonFormat_Short); + job.SetLocalAet(localAet); + job.SetRemoteModality(source); + + if (request.isMember(KEY_TIMEOUT)) + { + job.SetTimeout(SerializationToolbox::ReadUnsignedInteger(request, KEY_TIMEOUT)); + } + + for (Json::Value::ArrayIndex i = 0; i < request[KEY_RESOURCES].size(); i++) + { + DicomMap resource; + FromDcmtkBridge::FromJson(resource, request[KEY_RESOURCES][i], "Resources elements"); + + resource.SetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL, std::string(ResourceTypeToDicomQueryRetrieveLevel(level)), false); + + job.AddQuery(resource); + } + } /*************************************************************************** * DICOM C-Move SCU @@ -1569,53 +1661,15 @@ } ServerContext& context = OrthancRestApi::GetContext(call); - Json::Value request; - if (!call.ParseJsonRequest(request) || - request.type() != Json::objectValue || - !request.isMember(KEY_RESOURCES) || - !request.isMember(KEY_LEVEL) || - request[KEY_RESOURCES].type() != Json::arrayValue || - request[KEY_LEVEL].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON body containing fields " + - std::string(KEY_RESOURCES) + " and " + std::string(KEY_LEVEL)); - } - - ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); - - std::string localAet = Toolbox::GetJsonStringField - (request, KEY_LOCAL_AET, context.GetDefaultLocalApplicationEntityTitle()); + std::unique_ptr<DicomMoveScuJob> job(new DicomMoveScuJob(context)); + + ParseMoveGetJob(*job, request, call); + std::string targetAet = Toolbox::GetJsonStringField (request, KEY_TARGET_AET, context.GetDefaultLocalApplicationEntityTitle()); - - const RemoteModalityParameters source = - MyGetModalityUsingSymbolicName(call.GetUriComponent("id", "")); - - std::unique_ptr<DicomMoveScuJob> job(new DicomMoveScuJob(context)); - - job->SetQueryFormat(DicomToJsonFormat_Short); - - // QueryAccessor query(call); job->SetTargetAet(targetAet); - job->SetLocalAet(localAet); - job->SetRemoteModality(source); - - if (request.isMember(KEY_TIMEOUT)) - { - job->SetTimeout(SerializationToolbox::ReadUnsignedInteger(request, KEY_TIMEOUT)); - } - - for (Json::Value::ArrayIndex i = 0; i < request[KEY_RESOURCES].size(); i++) - { - DicomMap resource; - FromDcmtkBridge::FromJson(resource, request[KEY_RESOURCES][i], "Resources elements"); - - resource.SetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL, std::string(ResourceTypeToDicomQueryRetrieveLevel(level)), false); - - job->AddQuery(resource); - } OrthancRestApi::GetApi(call).SubmitCommandsJob (call, job.release(), true /* synchronous by default */, request); @@ -1623,6 +1677,51 @@ } + /*************************************************************************** + * DICOM C-Get SCU + ***************************************************************************/ + + static void DicomGet(RestApiPostCall& call) + { + if (call.IsDocumentation()) + { + OrthancRestApi::DocumentSubmitCommandsJob(call); + call.GetDocumentation() + .SetTag("Networking") + .SetSummary("Trigger C-GET SCU") + .SetDescription("Start a C-GET SCU command as a job, in order to retrieve DICOM resources " + "from a remote DICOM modality whose identifier is provided in the URL: ") + // "https://orthanc.uclouvain.be/book/users/rest.html#performing-c-move") // TODO-GET + .SetRequestField(KEY_RESOURCES, RestApiCallDocumentation::Type_JsonListOfObjects, + "List of queries identifying all the DICOM resources to be sent. " + "Usage of wildcards is prohibited and the query shall only contain DICOM ID tags. " + "Additionally, you may provide SOPClassesInStudy to limit the scope of the DICOM " + "negotiation to certain SOPClassUID or to present uncommon SOPClassUID during " + "the DICOM negotation. By default, " + "Orhanc will propose the most 120 common SOPClassUIDs.", true) + .SetRequestField(KEY_QUERY, RestApiCallDocumentation::Type_JsonObject, + "A query object identifying all the DICOM resources to be retrieved", true) + .SetRequestField(KEY_LOCAL_AET, RestApiCallDocumentation::Type_String, + "Local AET that is used for this commands, defaults to `DicomAet` configuration option. " + "Ignored if `DicomModalities` already sets `LocalAet` for this modality.", false) + .SetRequestField(KEY_TIMEOUT, RestApiCallDocumentation::Type_Number, + "Timeout for the C-GET command, in seconds", false) + .SetUriArgument("id", "Identifier of the modality of interest"); + return; + } + + ServerContext& context = OrthancRestApi::GetContext(call); + Json::Value request; + + std::unique_ptr<DicomGetScuJob> job(new DicomGetScuJob(context)); + + ParseMoveGetJob(*job, request, call); + + OrthancRestApi::GetApi(call).SubmitCommandsJob + (call, job.release(), true /* synchronous by default */, request); + return; + } + /*************************************************************************** * Orthanc Peers => Store client @@ -2213,7 +2312,7 @@ DicomFindAnswers answers(true); { - DicomControlUserConnection connection(GetAssociationParameters(call, json)); + DicomControlUserConnection connection(GetAssociationParameters(call, json), ScuOperationFlags_FindWorklist); connection.FindWorklist(answers, *query); } @@ -2544,6 +2643,7 @@ Register("/modalities/{id}/store", DicomStore); Register("/modalities/{id}/store-straight", DicomStoreStraight); // New in 1.6.1 Register("/modalities/{id}/move", DicomMove); + Register("/modalities/{id}/get", DicomGet); Register("/modalities/{id}/configuration", GetModalityConfiguration); // New in 1.8.1 // For Query/Retrieve
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -50,6 +50,8 @@ #include <boost/math/special_functions/round.hpp> #include <boost/shared_ptr.hpp> +#include "../../../OrthancFramework/Sources/FileStorage/StorageAccessor.h" + /** * This semaphore is used to limit the number of concurrent HTTP * requests on CPU-intensive routes of the REST API, in order to @@ -68,6 +70,14 @@ namespace Orthanc { + static ResourceType GetResourceTypeFromUri(const RestApiCall& call) + { + assert(!call.GetFullUri().empty()); + const std::string resourceType = call.GetFullUri() [0]; + return StringToResourceType(resourceType.c_str()); + } + + static std::string GetDocumentationSampleResource(ResourceType type) { switch (type) @@ -144,7 +154,7 @@ responseContent = static_cast<ResponseContentFlags>(static_cast<uint32_t>(responseContent) | ResponseContentFlags_Metadata); } - ResourceFinder finder(level, responseContent); + ResourceFinder finder(level, responseContent, context.GetFindStorageAccessMode(), context.GetIndex().HasFindSupport()); finder.SetOrthancId(level, identifier); finder.SetRetrieveMetadata(retrieveMetadata); @@ -154,77 +164,6 @@ // List all the patients, studies, series or instances ---------------------- - static void AnswerListOfResources1(RestApiOutput& output, - ServerContext& context, - const std::list<std::string>& resources, - const std::map<std::string, std::string>& instancesIds, // optional: the id of an instance for each found resource. - const std::map<std::string, boost::shared_ptr<DicomMap> >& resourcesMainDicomTags, // optional: all tags read from DB for a resource (current level and upper levels) - const std::map<std::string, boost::shared_ptr<Json::Value> >& resourcesDicomAsJson, // optional: the dicom-as-json for each resource - ResourceType level, - bool expand, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess) - { - Json::Value answer = Json::arrayValue; - - for (std::list<std::string>::const_iterator - resource = resources.begin(); resource != resources.end(); ++resource) - { - if (expand) - { - Json::Value expanded; - - std::map<std::string, std::string>::const_iterator instanceId = instancesIds.find(*resource); - if (instanceId != instancesIds.end()) // if it is found in instancesIds, it is also in resourcesDicomAsJson and mainDicomTags - { - // reuse data already collected before (e.g during lookup) - std::map<std::string, boost::shared_ptr<DicomMap> >::const_iterator mainDicomTags = resourcesMainDicomTags.find(*resource); - std::map<std::string, boost::shared_ptr<Json::Value> >::const_iterator dicomAsJson = resourcesDicomAsJson.find(*resource); - - context.ExpandResource(expanded, *resource, - *(mainDicomTags->second.get()), - instanceId->second, - dicomAsJson->second.get(), - level, format, requestedTags, allowStorageAccess); - } - else - { - context.ExpandResource(expanded, *resource, level, format, requestedTags, allowStorageAccess); - } - - if (expanded.type() == Json::objectValue) - { - answer.append(expanded); - } - } - else - { - answer.append(*resource); - } - } - - output.AnswerJson(answer); - } - - - static void AnswerListOfResources2(RestApiOutput& output, - ServerContext& context, - const std::list<std::string>& resources, - ResourceType level, - bool expand, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess) - { - std::map<std::string, std::string> unusedInstancesIds; - std::map<std::string, boost::shared_ptr<DicomMap> > unusedResourcesMainDicomTags; - std::map<std::string, boost::shared_ptr<Json::Value> > unusedResourcesDicomAsJson; - - AnswerListOfResources1(output, context, resources, unusedInstancesIds, unusedResourcesMainDicomTags, unusedResourcesDicomAsJson, level, expand, format, requestedTags, allowStorageAccess); - } - - template <enum ResourceType resourceType> static void ListResources(RestApiGetCall& call) { @@ -240,103 +179,54 @@ .SetDescription("List the Orthanc identifiers of all the available DICOM " + resources) .SetHttpGetArgument("limit", RestApiCallDocumentation::Type_Number, "Limit the number of results", false) .SetHttpGetArgument("since", RestApiCallDocumentation::Type_Number, "Show only the resources since the provided index", false) - .SetHttpGetArgument("expand", RestApiCallDocumentation::Type_String, - "If present, retrieve detailed information about the individual " + resources, false) .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information " "about the reported " + resources + " (if `expand` argument is provided)") .SetHttpGetSample("https://orthanc.uclouvain.be/demo/" + resources + "?since=0&limit=2", true); + OrthancRestApi::DocumentResponseContentAndExpand(call); return; } + + // TODO-FIND: include the FindRequest options parsing like since, limit in a method (parse from get-arguments and from post payload) + + std::set<DicomTag> requestedTags; + ResponseContentFlags responseContent; - ServerIndex& index = OrthancRestApi::GetIndex(call); - ServerContext& context = OrthancRestApi::GetContext(call); - - if (true) + OrthancRestApi::GetRequestedTags(requestedTags, call); + OrthancRestApi::GetResponseContentAndExpand(responseContent, call); + + ResourceFinder finder(resourceType, + responseContent, + OrthancRestApi::GetContext(call).GetFindStorageAccessMode(), + OrthancRestApi::GetContext(call).GetIndex().HasFindSupport()); + finder.AddRequestedTags(requestedTags); + + if (call.HasArgument("limit") || + call.HasArgument("since")) { - /** - * EXPERIMENTAL VERSION - **/ - - // TODO-FIND: include the FindRequest options parsing in a method (parse from get-arguments and from post payload) - // TODO-FIND: support other values for expand like expand=MainDicomTags,Labels,Parent,SeriesStatus - const bool expand = (call.HasArgument("expand") && - call.GetBooleanArgument("expand", true)); - - std::set<DicomTag> requestedTags; - OrthancRestApi::GetRequestedTags(requestedTags, call); - - ResourceFinder finder(resourceType, (expand ? ResponseContentFlags_ExpandTrue : ResponseContentFlags_ID)); - finder.AddRequestedTags(requestedTags); - - if (call.HasArgument("limit") || - call.HasArgument("since")) + if (!call.HasArgument("limit")) { - if (!call.HasArgument("limit")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"limit\" argument for GET request against: " + - call.FlattenUri()); - } - - if (!call.HasArgument("since")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"since\" argument for GET request against: " + - call.FlattenUri()); - } - - uint64_t since = boost::lexical_cast<uint64_t>(call.GetArgument("since", "")); - uint64_t limit = boost::lexical_cast<uint64_t>(call.GetArgument("limit", "")); - finder.SetLimitsSince(since); - finder.SetLimitsCount(limit); + throw OrthancException(ErrorCode_BadRequest, + "Missing \"limit\" argument for GET request against: " + + call.FlattenUri()); } - Json::Value answer; - finder.Execute(answer, context, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), false /* no "Metadata" field */); - call.GetOutput().AnswerJson(answer); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - - std::list<std::string> result; - - std::set<DicomTag> requestedTags; - OrthancRestApi::GetRequestedTags(requestedTags, call); - - if (call.HasArgument("limit") || - call.HasArgument("since")) + if (!call.HasArgument("since")) { - if (!call.HasArgument("limit")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"limit\" argument for GET request against: " + - call.FlattenUri()); - } - - if (!call.HasArgument("since")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"since\" argument for GET request against: " + - call.FlattenUri()); - } - - size_t since = boost::lexical_cast<size_t>(call.GetArgument("since", "")); - size_t limit = boost::lexical_cast<size_t>(call.GetArgument("limit", "")); - index.GetAllUuids(result, resourceType, since, limit); + throw OrthancException(ErrorCode_BadRequest, + "Missing \"since\" argument for GET request against: " + + call.FlattenUri()); } - else - { - index.GetAllUuids(result, resourceType); - } - - AnswerListOfResources2(call.GetOutput(), context, result, resourceType, call.HasArgument("expand") && call.GetBooleanArgument("expand", true), - OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), - requestedTags, - true /* allowStorageAccess */); + + uint64_t since = boost::lexical_cast<uint64_t>(call.GetArgument("since", "")); + uint64_t limit = boost::lexical_cast<uint64_t>(call.GetArgument("limit", "")); + finder.SetLimitsSince(since); + finder.SetLimitsCount(limit); } + + Json::Value answer; + finder.Execute(answer, OrthancRestApi::GetContext(call), + OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), false /* no "Metadata" field */); + call.GetOutput().AnswerJson(answer); } @@ -360,39 +250,22 @@ return; } - const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); - std::set<DicomTag> requestedTags; OrthancRestApi::GetRequestedTags(requestedTags, call); - if (true) + const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); + + ResourceFinder finder(resourceType, + ResponseContentFlags_ExpandTrue, + OrthancRestApi::GetContext(call).GetFindStorageAccessMode(), + OrthancRestApi::GetContext(call).GetIndex().HasFindSupport()); + finder.AddRequestedTags(requestedTags); + finder.SetOrthancId(resourceType, call.GetUriComponent("id", "")); + + Json::Value json; + if (finder.ExecuteOneResource(json, OrthancRestApi::GetContext(call), format, false /* no "Metadata" field */)) { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(resourceType, ResponseContentFlags_ExpandTrue); - finder.AddRequestedTags(requestedTags); - finder.SetOrthancId(resourceType, call.GetUriComponent("id", "")); - - Json::Value json; - if (finder.ExecuteOneResource(json, OrthancRestApi::GetContext(call), format, false /* no "Metadata" field */)) - { - call.GetOutput().AnswerJson(json); - } - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - - Json::Value json; - if (OrthancRestApi::GetContext(call).ExpandResource( - json, call.GetUriComponent("id", ""), resourceType, format, requestedTags, true /* allowStorageAccess */)) - { - call.GetOutput().AnswerJson(json); - } + call.GetOutput().AnswerJson(json); } } @@ -541,7 +414,16 @@ else { // return the attachment without any transcoding - context.AnswerAttachment(call.GetOutput(), publicId, FileContentType_Dicom); + FileInfo info; + int64_t revision; + if (!context.GetIndex().LookupAttachment(info, revision, ResourceType_Instance, publicId, FileContentType_Dicom)) + { + throw OrthancException(ErrorCode_UnknownResource); + } + else + { + context.AnswerAttachment(call.GetOutput(), info); + } } } @@ -1718,12 +1600,13 @@ static void GetResourceStatistics(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get " + r + " statistics") .SetDescription("Get statistics about the given " + r) .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -1744,9 +1627,9 @@ "Size on the disk of the uncompressed DICOM instances associated with the " + r + ", expressed in bytes") .SetAnswerField("DicomUncompressedSizeMB", RestApiCallDocumentation::Type_Number, "Size on the disk of the uncompressed DICOM instances associated with the " + r + ", expressed in megabytes (MB)") - .SetHttpGetSample(GetDocumentationSampleResource(t) + "/statistics", true); - - switch (t) + .SetHttpGetSample(GetDocumentationSampleResource(level) + "/statistics", true); + + switch (level) { // Do NOT add "break" below this point! case ResourceType_Patient: @@ -1815,22 +1698,15 @@ // Handling of metadata ----------------------------------------------------- - static void CheckValidResourceType(const RestApiCall& call) - { - assert(!call.GetFullUri().empty()); - const std::string resourceType = call.GetFullUri() [0]; - StringToResourceType(resourceType.c_str()); - } - - static void ListMetadata(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("List metadata") .SetDescription("Get the list of metadata that are associated with the given " + r) .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -1840,13 +1716,12 @@ "If present, use the numeric identifier of the metadata instead of its symbolic name", false) .AddAnswerType(MimeType_Json, "JSON array containing the names of the available metadata, " "or JSON associative array mapping metadata to their values (if `expand` argument is provided)") - .SetHttpGetSample(GetDocumentationSampleResource(t) + "/metadata", true); + .SetHttpGetSample(GetDocumentationSampleResource(level) + "/metadata", true); return; } assert(!call.GetFullUri().empty()); const std::string publicId = call.GetUriComponent("id", ""); - ResourceType level = StringToResourceType(call.GetFullUri() [0].c_str()); typedef std::map<MetadataType, std::string> Metadata; @@ -1978,12 +1853,13 @@ static void GetMetadata(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get metadata") .SetDescription("Get the value of a metadata that is associated with the given " + r) .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -1996,7 +1872,6 @@ assert(!call.GetFullUri().empty()); const std::string publicId = call.GetUriComponent("id", ""); - const ResourceType level = StringToResourceType(call.GetFullUri() [0].c_str()); std::string name = call.GetUriComponent("name", ""); MetadataType metadata = StringToMetadata(name); @@ -2025,12 +1900,13 @@ static void DeleteMetadata(RestApiDeleteCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Delete metadata") .SetDescription("Delete some metadata associated with the given DICOM " + r + ". This call will fail if trying to delete a system metadata (i.e. whose index is < 1024).") @@ -2041,7 +1917,6 @@ return; } - CheckValidResourceType(call); const std::string publicId = call.GetUriComponent("id", ""); std::string name = call.GetUriComponent("name", ""); @@ -2089,12 +1964,13 @@ static void SetMetadata(RestApiPutCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Set metadata") .SetDescription("Set the value of some metadata in the given DICOM " + r + ". This call will fail if trying to modify a system metadata (i.e. whose index is < 1024).") @@ -2105,8 +1981,6 @@ return; } - CheckValidResourceType(call); - std::string publicId = call.GetUriComponent("id", ""); std::string name = call.GetUriComponent("name", ""); MetadataType metadata = StringToMetadata(name); @@ -2154,23 +2028,22 @@ static void ListLabels(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("List labels") .SetDescription("Get the labels that are associated with the given " + r + " (new in Orthanc 1.12.0)") .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") .AddAnswerType(MimeType_Json, "JSON array containing the names of the labels") - .SetHttpGetSample(GetDocumentationSampleResource(t) + "/labels", true); + .SetHttpGetSample(GetDocumentationSampleResource(level) + "/labels", true); return; } - assert(!call.GetFullUri().empty()); const std::string publicId = call.GetUriComponent("id", ""); - ResourceType level = StringToResourceType(call.GetFullUri() [0].c_str()); std::set<std::string> labels; OrthancRestApi::GetIndex(call).ListLabels(labels, publicId, level); @@ -2188,12 +2061,13 @@ static void GetLabel(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Test label") .SetDescription("Test whether the " + r + " is associated with the given label") .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -2202,11 +2076,7 @@ return; } - CheckValidResourceType(call); - - assert(!call.GetFullUri().empty()); const std::string publicId = call.GetUriComponent("id", ""); - const ResourceType level = StringToResourceType(call.GetFullUri() [0].c_str()); std::string label = call.GetUriComponent("label", ""); @@ -2222,12 +2092,13 @@ static void AddLabel(RestApiPutCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Add label") .SetDescription("Associate a label with a " + r) .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -2235,10 +2106,7 @@ return; } - CheckValidResourceType(call); - std::string publicId = call.GetUriComponent("id", ""); - const ResourceType level = StringToResourceType(call.GetFullUri() [0].c_str()); std::string label = call.GetUriComponent("label", ""); OrthancRestApi::GetIndex(call).ModifyLabel(publicId, level, label, StatelessDatabaseOperations::LabelOperation_Add); @@ -2249,12 +2117,13 @@ static void RemoveLabel(RestApiDeleteCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Remove label") .SetDescription("Remove a label associated with a " + r) .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -2262,10 +2131,7 @@ return; } - CheckValidResourceType(call); - std::string publicId = call.GetUriComponent("id", ""); - const ResourceType level = StringToResourceType(call.GetFullUri() [0].c_str()); std::string label = call.GetUriComponent("label", ""); OrthancRestApi::GetIndex(call).ModifyLabel(publicId, level, label, StatelessDatabaseOperations::LabelOperation_Remove); @@ -2278,26 +2144,26 @@ static void ListAttachments(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("List attachments") .SetDescription("Get the list of attachments that are associated with the given " + r) .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") .SetHttpGetArgument("full", RestApiCallDocumentation::Type_String, "If present, retrieve the attachments list and their numerical ids", false) .AddAnswerType(MimeType_Json, "JSON array containing the names of the attachments") - .SetHttpGetSample(GetDocumentationSampleResource(t) + "/attachments", true); + .SetHttpGetSample(GetDocumentationSampleResource(level) + "/attachments", true); return; } - const std::string resourceType = call.GetFullUri() [0]; const std::string publicId = call.GetUriComponent("id", ""); std::set<FileContentType> attachments; - OrthancRestApi::GetIndex(call).ListAvailableAttachments(attachments, publicId, StringToResourceType(resourceType.c_str())); + OrthancRestApi::GetIndex(call).ListAvailableAttachments(attachments, publicId, level); Json::Value result; @@ -2306,7 +2172,7 @@ result = Json::objectValue; for (std::set<FileContentType>::const_iterator - it = attachments.begin(); it != attachments.end(); ++it) + it = attachments.begin(); it != attachments.end(); ++it) { std::string key = EnumerationToString(*it); result[key] = static_cast<uint16_t>(*it); @@ -2317,7 +2183,7 @@ result = Json::arrayValue; for (std::set<FileContentType>::const_iterator - it = attachments.begin(); it != attachments.end(); ++it) + it = attachments.begin(); it != attachments.end(); ++it) { result.append(EnumerationToString(*it)); } @@ -2338,17 +2204,15 @@ } - static bool GetAttachmentInfo(FileInfo& info, + static bool GetAttachmentInfo(FileInfo& info /* out */, + int64_t& revision /* out */, + ResourceType level, RestApiGetCall& call) { - CheckValidResourceType(call); - const std::string publicId = call.GetUriComponent("id", ""); - const std::string name = call.GetUriComponent("name", ""); - FileContentType contentType = StringToContentType(name); - - int64_t revision; - if (OrthancRestApi::GetIndex(call).LookupAttachment(info, revision, publicId, contentType)) + FileContentType contentType = StringToContentType(call.GetUriComponent("name", "")); + + if (OrthancRestApi::GetIndex(call).LookupAttachment(info, revision, level, publicId, contentType)) { SetAttachmentETag(call.GetOutput(), revision, info); // New in Orthanc 1.9.2 @@ -2375,10 +2239,11 @@ static void GetAttachmentOperations(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); AddAttachmentDocumentation(call, r); call.GetDocumentation() .SetTag("Other") @@ -2390,7 +2255,8 @@ } FileInfo info; - if (GetAttachmentInfo(info, call)) + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call)) { Json::Value operations = Json::arrayValue; @@ -2429,12 +2295,13 @@ template <int uncompress> static void GetAttachmentData(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get attachment" + std::string(uncompress ? "" : " (no decompression)")) .SetDescription("Get the (binary) content of one attachment associated with the given " + r + std::string(uncompress ? "" : ". The attachment will not be decompressed if `StorageCompression` is `true`.")) @@ -2442,46 +2309,60 @@ .SetUriArgument("name", "The name of the attachment, or its index (cf. `UserContentType` configuration option)") .AddAnswerType(MimeType_Binary, "The attachment") .SetAnswerHeader("ETag", "Revision of the attachment, to be used in further `PUT` or `DELETE` operations") - .SetHttpHeader("If-None-Match", "Optional revision of the metadata, to check if its content has changed"); + .SetHttpHeader("If-None-Match", "Optional revision of the attachment, to check if its content has changed") + .SetHttpHeader("Content-Range", "Optional content range to access part of the attachment (new in Orthanc 1.12.5)"); return; } ServerContext& context = OrthancRestApi::GetContext(call); - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - FileContentType type = StringToContentType(call.GetUriComponent("name", "")); + bool hasRangeHeader = false; + StorageAccessor::Range range; + + HttpToolbox::Arguments::const_iterator rangeHeader = call.GetHttpHeaders().find("range"); + if (rangeHeader != call.GetHttpHeaders().end()) + { + hasRangeHeader = true; + range = StorageAccessor::Range::ParseHttpRange(rangeHeader->second); + } FileInfo info; - if (GetAttachmentInfo(info, call)) + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call)) { // NB: "SetAttachmentETag()" is already invoked by "GetAttachmentInfo()" - if (uncompress) + int64_t userRevision; + std::string userMD5; + if (GetRevisionHeader(userRevision, userMD5, call, "If-None-Match") && + revision == userRevision && + info.GetUncompressedMD5() == userMD5) + { + call.GetOutput().GetLowLevelOutput().SendStatus(HttpStatus_304_NotModified); + return; + } + + if (hasRangeHeader) { - context.AnswerAttachment(call.GetOutput(), publicId, type); + std::string fragment; + context.ReadAttachmentRange(fragment, info, range, uncompress); + + uint64_t fullSize = (uncompress ? info.GetUncompressedSize() : info.GetCompressedSize()); + call.GetOutput().GetLowLevelOutput().SetContentType(MimeType_Binary); + call.GetOutput().GetLowLevelOutput().AddHeader("Content-Range", range.FormatHttpContentRange(fullSize)); + call.GetOutput().GetLowLevelOutput().SendStatus(HttpStatus_206_PartialContent, fragment); + } + else if (uncompress || + info.GetCompressionType() == CompressionType_None) + { + context.AnswerAttachment(call.GetOutput(), info); } else { - // Return the raw data (possibly compressed), as stored on the filesystem + // Access to the raw attachment (which is compressed) std::string content; - std::string attachmentId; - int64_t revision; - context.ReadAttachment(content, revision, attachmentId, publicId, type, false, true /* skipCache when you absolutely need the compressed data */); - - int64_t userRevision; - std::string userMD5; - if (GetRevisionHeader(userRevision, userMD5, call, "If-None-Match") && - revision == userRevision && - info.GetUncompressedMD5() == userMD5) - { - call.GetOutput().GetLowLevelOutput().SendStatus(HttpStatus_304_NotModified); - } - else - { - call.GetOutput().AnswerBuffer(content, MimeType_Binary); - } + context.ReadAttachment(content, info, false /* don't uncompress */, true /* skip cache */); + call.GetOutput().AnswerBuffer(content, MimeType_Binary); } } } @@ -2489,13 +2370,14 @@ static void GetAttachmentSize(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); AddAttachmentDocumentation(call, r); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get size of attachment") .SetDescription("Get the size of one attachment associated with the given " + r) .AddAnswerType(MimeType_PlainText, "The size of the attachment"); @@ -2503,7 +2385,8 @@ } FileInfo info; - if (GetAttachmentInfo(info, call)) + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call)) { call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedSize()), MimeType_PlainText); } @@ -2511,13 +2394,14 @@ static void GetAttachmentInfo(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); AddAttachmentDocumentation(call, r); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get info about the attachment") .SetDescription("Get all the information about the attachment associated with the given " + r) .AddAnswerType(MimeType_Json, "JSON object containing the information about the attachment") @@ -2526,7 +2410,8 @@ } FileInfo info; - if (GetAttachmentInfo(info, call)) + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call)) { Json::Value result = Json::objectValue; result["Uuid"] = info.GetUuid(); @@ -2542,13 +2427,14 @@ static void GetAttachmentCompressedSize(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); AddAttachmentDocumentation(call, r); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get size of attachment on disk") .SetDescription("Get the size of one attachment associated with the given " + r + ", as stored on the disk. " "This is different from `.../size` iff `EnableStorage` is `true`.") @@ -2557,7 +2443,8 @@ } FileInfo info; - if (GetAttachmentInfo(info, call)) + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call)) { call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedSize()), MimeType_PlainText); } @@ -2566,13 +2453,14 @@ static void GetAttachmentMD5(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); AddAttachmentDocumentation(call, r); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get MD5 of attachment") .SetDescription("Get the MD5 hash of one attachment associated with the given " + r) .AddAnswerType(MimeType_PlainText, "The MD5 of the attachment"); @@ -2580,7 +2468,8 @@ } FileInfo info; - if (GetAttachmentInfo(info, call) && + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call) && info.GetUncompressedMD5() != "") { call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedMD5()), MimeType_PlainText); @@ -2590,13 +2479,14 @@ static void GetAttachmentCompressedMD5(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); AddAttachmentDocumentation(call, r); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get MD5 of attachment on disk") .SetDescription("Get the MD5 hash of one attachment associated with the given " + r + ", as stored on the disk. " "This is different from `.../md5` iff `EnableStorage` is `true`.") @@ -2605,7 +2495,8 @@ } FileInfo info; - if (GetAttachmentInfo(info, call) && + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call) && info.GetCompressedMD5() != "") { call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedMD5()), MimeType_PlainText); @@ -2615,12 +2506,13 @@ static void VerifyAttachment(RestApiPostCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Verify attachment") .SetDescription("Verify that the attachment is not corrupted, by validating its MD5 hash") .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -2630,7 +2522,6 @@ } ServerContext& context = OrthancRestApi::GetContext(call); - CheckValidResourceType(call); std::string publicId = call.GetUriComponent("id", ""); std::string name = call.GetUriComponent("name", ""); @@ -2638,7 +2529,7 @@ FileInfo info; int64_t revision; // Ignored - if (!OrthancRestApi::GetIndex(call).LookupAttachment(info, revision, publicId, contentType) || + if (!OrthancRestApi::GetIndex(call).LookupAttachment(info, revision, level, publicId, contentType) || info.GetCompressedMD5() == "" || info.GetUncompressedMD5() == "") { @@ -2650,9 +2541,7 @@ // First check whether the compressed data is correctly stored in the disk std::string data; - std::string attachmentId; - - context.ReadAttachment(data, revision, attachmentId, publicId, StringToContentType(name), false, true /* skipCache when you absolutely need the compressed data */); + context.ReadAttachment(data, info, false, true /* skipCache when you absolutely need the compressed data */); std::string actualMD5; Toolbox::ComputeMD5(actualMD5, data); @@ -2667,7 +2556,7 @@ } else { - context.ReadAttachment(data, revision, attachmentId, publicId, StringToContentType(name), true, true /* skipCache when you absolutely need the compressed data */); + context.ReadAttachment(data, info, true, true /* skipCache when you absolutely need the compressed data */); Toolbox::ComputeMD5(actualMD5, data); ok = (actualMD5 == info.GetUncompressedMD5()); } @@ -2687,12 +2576,13 @@ static void UploadAttachment(RestApiPutCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Set attachment") .SetDescription("Attach a file to the given DICOM " + r + ". This call will fail if trying to modify a system attachment (i.e. whose index is < 1024).") @@ -2705,11 +2595,9 @@ } ServerContext& context = OrthancRestApi::GetContext(call); - CheckValidResourceType(call); std::string publicId = call.GetUriComponent("id", ""); std::string name = call.GetUriComponent("name", ""); - ResourceType resourceType = StringToResourceType(call.GetFullUri()[0].c_str()); FileContentType contentType = StringToContentType(name); if (IsUserContentType(contentType) || // It is forbidden to modify internal attachments... @@ -2734,7 +2622,7 @@ } int64_t newRevision; - context.AddAttachment(newRevision, publicId, resourceType, StringToContentType(name), call.GetBodyData(), + context.AddAttachment(newRevision, publicId, level, StringToContentType(name), call.GetBodyData(), call.GetBodySize(), hasOldRevision, oldRevision, oldMD5); SetBufferContentETag(call.GetOutput(), newRevision, call.GetBodyData(), call.GetBodySize()); // New in Orthanc 1.9.2 @@ -2749,12 +2637,13 @@ static void DeleteAttachment(RestApiDeleteCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Delete attachment") .SetDescription("Delete an attachment associated with the given DICOM " + r + ". This call will fail if trying to delete a system attachment (i.e. whose index is < 1024).") @@ -2765,8 +2654,6 @@ return; } - CheckValidResourceType(call); - std::string publicId = call.GetUriComponent("id", ""); std::string name = call.GetUriComponent("name", ""); FileContentType contentType = StringToContentType(name); @@ -2838,12 +2725,13 @@ template <enum CompressionType compression> static void ChangeAttachmentCompression(RestApiPostCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary(compression == CompressionType_None ? "Uncompress attachment" : "Compress attachment") .SetDescription("Change the compression scheme that is used to store an attachment.") .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") @@ -2851,27 +2739,25 @@ return; } - CheckValidResourceType(call); - std::string publicId = call.GetUriComponent("id", ""); std::string name = call.GetUriComponent("name", ""); - ResourceType resourceType = StringToResourceType(call.GetFullUri()[0].c_str()); FileContentType contentType = StringToContentType(name); - OrthancRestApi::GetContext(call).ChangeAttachmentCompression(publicId, resourceType, contentType, compression); + OrthancRestApi::GetContext(call).ChangeAttachmentCompression(level, publicId, contentType, compression); call.GetOutput().AnswerBuffer("{}", MimeType_Json); } static void IsAttachmentCompressed(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); AddAttachmentDocumentation(call, r); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Is attachment compressed?") .SetDescription("Test whether the attachment has been stored as a compressed file on the disk.") .AddAnswerType(MimeType_PlainText, "`0` if the attachment was stored uncompressed, `1` if it was compressed"); @@ -2879,7 +2765,8 @@ } FileInfo info; - if (GetAttachmentInfo(info, call)) + int64_t revision; + if (GetAttachmentInfo(info, revision, level, call)) { std::string answer = (info.GetCompressionType() == CompressionType_None) ? "0" : "1"; call.GetOutput().AnswerBuffer(answer, MimeType_PlainText); @@ -2917,12 +2804,13 @@ static bool ExtractSharedTags(Json::Value& shared, ServerContext& context, - const std::string& publicId) + const std::string& publicId, + ResourceType level) { // Retrieve all the instances of this patient/study/series typedef std::list<std::string> Instances; Instances instances; - context.GetIndex().GetChildInstances(instances, publicId); // (*) + context.GetIndex().GetChildInstances(instances, publicId, level); // (*) // Loop over the instances bool isFirst = true; @@ -2992,20 +2880,21 @@ static void GetSharedTags(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full); - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get shared tags") .SetDescription("Extract the DICOM tags whose value is constant across all the child instances of " "the DICOM " + r + " whose Orthanc identifier is provided in the URL") .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest") .AddAnswerType(MimeType_Json, "JSON object containing the values of the DICOM tags") - .SetTruncatedJsonHttpGetSample(GetDocumentationSampleResource(t) + "/shared-tags", 5); + .SetTruncatedJsonHttpGetSample(GetDocumentationSampleResource(level) + "/shared-tags", 5); return; } @@ -3013,7 +2902,7 @@ std::string publicId = call.GetUriComponent("id", ""); Json::Value sharedTags; - if (ExtractSharedTags(sharedTags, context, publicId)) + if (ExtractSharedTags(sharedTags, context, publicId, level)) { // Success: Send the value of the shared tags AnswerDicomAsJson(call, sharedTags, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full)); @@ -3088,7 +2977,7 @@ // Retrieve all the instances of this patient/study/series typedef std::list<std::string> Instances; Instances instances; - context.GetIndex().GetChildInstances(instances, publicId); + context.GetIndex().GetChildInstances(instances, publicId, resourceType); if (instances.empty()) { @@ -3183,70 +3072,14 @@ } - namespace + enum FindType { - class FindVisitor : public ServerContext::ILookupVisitor - { - private: - bool isComplete_; - std::list<std::string> resources_; - FindStorageAccessMode findStorageAccessMode_; - - // cache the data we used during lookup and that we could reuse when building the answers - std::map<std::string, std::string> instancesIds_; // the id of an instance for each found resource. - std::map<std::string, boost::shared_ptr<DicomMap> > resourcesMainDicomTags_; // all tags read from DB for a resource (current level and upper levels) - std::map<std::string, boost::shared_ptr<Json::Value> > resourcesDicomAsJson_; // the dicom-as-json for a resource - - DicomToJsonFormat format_; - - public: - explicit FindVisitor(DicomToJsonFormat format, FindStorageAccessMode findStorageAccessMode) : - isComplete_(false), - findStorageAccessMode_(findStorageAccessMode), - format_(format) - { - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - isComplete_ = true; // Unused information as of Orthanc 1.5.0 - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson) ORTHANC_OVERRIDE - { - resources_.push_back(publicId); - instancesIds_[publicId] = instanceId; - resourcesMainDicomTags_[publicId].reset(mainDicomTags.Clone()); - if (dicomAsJson != NULL) - { - resourcesDicomAsJson_[publicId].reset(new Json::Value(*dicomAsJson)); // keep our own copy because we might reuse it between lookup and answers - } - else - { - resourcesDicomAsJson_[publicId] = boost::shared_ptr<Json::Value>(); - } - } - - void Answer(RestApiOutput& output, - ServerContext& context, - ResourceType level, - bool expand, - const std::set<DicomTag>& requestedTags) const - { - AnswerListOfResources1(output, context, resources_, instancesIds_, resourcesMainDicomTags_, resourcesDicomAsJson_, level, expand, format_, requestedTags, IsStorageAccessAllowedForAnswers(findStorageAccessMode_)); - } - }; - } - - + FindType_Find, + FindType_Count + }; + + + template <enum FindType requestType> static void Find(RestApiPostCall& call) { static const char* const KEY_CASE_SENSITIVE = "CaseSensitive"; @@ -3265,57 +3098,64 @@ static const char* const KEY_PARENT_PATIENT = "ParentPatient"; // New in Orthanc 1.12.5 static const char* const KEY_PARENT_STUDY = "ParentStudy"; // New in Orthanc 1.12.5 static const char* const KEY_PARENT_SERIES = "ParentSeries"; // New in Orthanc 1.12.5 - static const char* const KEY_QUERY_METADATA = "QueryMetadata"; // New in Orthanc 1.12.5 + static const char* const KEY_METADATA_QUERY = "MetadataQuery"; // New in Orthanc 1.12.5 static const char* const KEY_RESPONSE_CONTENT = "ResponseContent"; // New in Orthanc 1.12.5 if (call.IsDocumentation()) { OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human); - call.GetDocumentation() - .SetTag("System") - .SetSummary("Look for local resources") - .SetDescription("This URI can be used to perform a search on the content of the local Orthanc server, " - "in a way that is similar to querying remote DICOM modalities using C-FIND SCU: " - "https://orthanc.uclouvain.be/book/users/rest.html#performing-finds-within-orthanc") - .SetRequestField(KEY_CASE_SENSITIVE, RestApiCallDocumentation::Type_Boolean, - "Enable case-sensitive search for PN value representations (defaults to configuration option `CaseSensitivePN`)", false) - .SetRequestField(KEY_EXPAND, RestApiCallDocumentation::Type_Boolean, - "Also retrieve the content of the matching resources, not only their Orthanc identifiers", false) + RestApiCallDocumentation& doc = call.GetDocumentation(); + + doc.SetTag("System") .SetRequestField(KEY_LEVEL, RestApiCallDocumentation::Type_String, "Level of the query (`Patient`, `Study`, `Series` or `Instance`)", true) - .SetRequestField(KEY_LIMIT, RestApiCallDocumentation::Type_Number, - "Limit the number of reported resources", false) - .SetRequestField(KEY_SINCE, RestApiCallDocumentation::Type_Number, - "Show only the resources since the provided index (in conjunction with `Limit`)", false) - .SetRequestField(KEY_REQUESTED_TAGS, RestApiCallDocumentation::Type_JsonListOfStrings, - "A list of DICOM tags to include in the response (applicable only if \"Expand\" is set to true). " - "The tags requested tags are returned in the 'RequestedTags' field in the response. " - "Note that, if you are requesting tags that are not listed in the Main Dicom Tags stored in DB, building the response " - "might be slow since Orthanc will need to access the DICOM files. If not specified, Orthanc will return " - "all Main Dicom Tags to keep backward compatibility with Orthanc prior to 1.11.0.", false) .SetRequestField(KEY_QUERY, RestApiCallDocumentation::Type_JsonObject, "Associative array containing the filter on the values of the DICOM tags", true) .SetRequestField(KEY_LABELS, RestApiCallDocumentation::Type_JsonListOfStrings, "List of strings specifying which labels to look for in the resources (new in Orthanc 1.12.0)", true) .SetRequestField(KEY_LABELS_CONSTRAINT, RestApiCallDocumentation::Type_String, "Constraint on the labels, can be `All`, `Any`, or `None` (defaults to `All`, new in Orthanc 1.12.0)", true) - .SetRequestField(KEY_ORDER_BY, RestApiCallDocumentation::Type_JsonListOfObjects, - "Array of associative arrays containing the requested ordering (new in Orthanc 1.12.5)", true) .SetRequestField(KEY_PARENT_PATIENT, RestApiCallDocumentation::Type_String, "Limit the reported resources to descendants of this patient (new in Orthanc 1.12.5)", true) .SetRequestField(KEY_PARENT_STUDY, RestApiCallDocumentation::Type_String, "Limit the reported resources to descendants of this study (new in Orthanc 1.12.5)", true) .SetRequestField(KEY_PARENT_SERIES, RestApiCallDocumentation::Type_String, "Limit the reported resources to descendants of this series (new in Orthanc 1.12.5)", true) - .SetRequestField(KEY_QUERY_METADATA, RestApiCallDocumentation::Type_JsonObject, - "Associative array containing the filter on the values of the metadata (new in Orthanc 1.12.5)", true) - .SetRequestField(KEY_RESPONSE_CONTENT, RestApiCallDocumentation::Type_JsonListOfStrings, - "Defines the content of response for each returned resource. Allowed values are `MainDicomTags`, " - "`Metadata`, `Children`, `Parent`, `Labels`, `Status`, `IsStable`, `Attachments`. " - "(new in Orthanc 1.12.5)", true) - .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information " - "about the reported resources (if `Expand` argument is `true`)"); + .SetRequestField(KEY_METADATA_QUERY, RestApiCallDocumentation::Type_JsonObject, + "Associative array containing the filter on the values of the metadata (new in Orthanc 1.12.5)", true); + + switch (requestType) + { + case FindType_Find: + doc.SetSummary("Look for local resources") + .SetRequestField(KEY_CASE_SENSITIVE, RestApiCallDocumentation::Type_Boolean, + "Enable case-sensitive search for PN value representations (defaults to configuration option `CaseSensitivePN`)", false) + .SetDescription("This URI can be used to perform a search on the content of the local Orthanc server, " + "in a way that is similar to querying remote DICOM modalities using C-FIND SCU: " + "https://orthanc.uclouvain.be/book/users/rest.html#performing-finds-within-orthanc") + .SetRequestField(KEY_LIMIT, RestApiCallDocumentation::Type_Number, + "Limit the number of reported resources", false) + .SetRequestField(KEY_SINCE, RestApiCallDocumentation::Type_Number, + "Show only the resources since the provided index (in conjunction with `Limit`)", false) + .SetRequestField(KEY_ORDER_BY, RestApiCallDocumentation::Type_JsonListOfObjects, + "Array of associative arrays containing the requested ordering (new in Orthanc 1.12.5)", true) + .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information " + "about the reported resources (if `Expand` argument is `true`)"); + + OrthancRestApi::DocumentRequestedTags(call); + OrthancRestApi::DocumentResponseContentAndExpand(call); + break; + case FindType_Count: + doc.SetSummary("Count local resources") + .SetDescription("This URI can be used to count the resources that are matching criteria on the content of the local Orthanc server, " + "in a way that is similar to tools/find") + .AddAnswerType(MimeType_Json, "A JSON object with the `Count` of matching resources"); + break; + default: + throw OrthancException(ErrorCode_NotImplemented); + } + return; } @@ -3346,30 +3186,6 @@ throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_CASE_SENSITIVE) + "\" must be a Boolean"); } - else if (request.isMember(KEY_LIMIT) && - request[KEY_LIMIT].type() != Json::intValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_LIMIT) + "\" must be an integer"); - } - else if (request.isMember(KEY_SINCE) && - request[KEY_SINCE].type() != Json::intValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_SINCE) + "\" must be an integer"); - } - else if (request.isMember(KEY_REQUESTED_TAGS) && - request[KEY_REQUESTED_TAGS].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_REQUESTED_TAGS) + "\" must be an array"); - } - else if (request.isMember(KEY_RESPONSE_CONTENT) && - request[KEY_RESPONSE_CONTENT].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_RESPONSE_CONTENT) + "\" must be an array"); - } else if (request.isMember(KEY_LABELS) && request[KEY_LABELS].type() != Json::arrayValue) { @@ -3382,17 +3198,11 @@ throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be an array of strings"); } - else if (request.isMember(KEY_ORDER_BY) && - request[KEY_ORDER_BY].type() != Json::arrayValue) + else if (request.isMember(KEY_METADATA_QUERY) && + request[KEY_METADATA_QUERY].type() != Json::objectValue) { throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_ORDER_BY) + "\" must be an array"); - } - else if (request.isMember(KEY_QUERY_METADATA) && - request[KEY_QUERY_METADATA].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_QUERY_METADATA) + "\" must be an JSON object"); + "Field \"" + std::string(KEY_METADATA_QUERY) + "\" must be an JSON object"); } else if (request.isMember(KEY_PARENT_PATIENT) && request[KEY_PARENT_PATIENT].type() != Json::stringValue) @@ -3412,72 +3222,88 @@ throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_PARENT_SERIES) + "\" must be a string"); } + else if (requestType == FindType_Find && request.isMember(KEY_LIMIT) && + request[KEY_LIMIT].type() != Json::intValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Field \"" + std::string(KEY_LIMIT) + "\" must be an integer"); + } + else if (requestType == FindType_Find && request.isMember(KEY_SINCE) && + request[KEY_SINCE].type() != Json::intValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Field \"" + std::string(KEY_SINCE) + "\" must be an integer"); + } + else if (requestType == FindType_Find && request.isMember(KEY_REQUESTED_TAGS) && + request[KEY_REQUESTED_TAGS].type() != Json::arrayValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Field \"" + std::string(KEY_REQUESTED_TAGS) + "\" must be an array"); + } + else if (requestType == FindType_Find && request.isMember(KEY_RESPONSE_CONTENT) && + request[KEY_RESPONSE_CONTENT].type() != Json::arrayValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Field \"" + std::string(KEY_RESPONSE_CONTENT) + "\" must be an array"); + } + else if (requestType == FindType_Find && request.isMember(KEY_ORDER_BY) && + request[KEY_ORDER_BY].type() != Json::arrayValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Field \"" + std::string(KEY_ORDER_BY) + "\" must be an array"); + } else if (true) { - /** - * EXPERIMENTAL VERSION - **/ - ResponseContentFlags responseContent = ResponseContentFlags_ID; - if (request.isMember(KEY_RESPONSE_CONTENT)) + if (requestType == FindType_Find) { - responseContent = ResponseContentFlags_Default; - - for (Json::ArrayIndex i = 0; i < request[KEY_RESPONSE_CONTENT].size(); ++i) + if (request.isMember(KEY_RESPONSE_CONTENT)) { - responseContent = static_cast<ResponseContentFlags>(static_cast<uint32_t>(responseContent) | StringToResponseContent(request[KEY_RESPONSE_CONTENT][i].asString())); + responseContent = ResponseContentFlags_Default; + + for (Json::ArrayIndex i = 0; i < request[KEY_RESPONSE_CONTENT].size(); ++i) + { + responseContent = static_cast<ResponseContentFlags>(static_cast<uint32_t>(responseContent) | StringToResponseContent(request[KEY_RESPONSE_CONTENT][i].asString())); + } + } + else if (request.isMember(KEY_EXPAND) && request[KEY_EXPAND].asBool()) + { + responseContent = ResponseContentFlags_ExpandTrue; } } - else if (request.isMember(KEY_EXPAND) && request[KEY_EXPAND].asBool()) + else if (requestType == FindType_Count) { - responseContent = ResponseContentFlags_ExpandTrue; + responseContent = ResponseContentFlags_INTERNAL_CountResources; } const ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); - ResourceFinder finder(level, responseContent); - finder.SetDatabaseLimits(context.GetDatabaseLimits(level)); - - const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human); - - if (request.isMember(KEY_LIMIT)) - { - int64_t tmp = request[KEY_LIMIT].asInt64(); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_LIMIT) + "\" must be a positive integer"); - } - else if (tmp != 0) // This is for compatibility with Orthanc 1.12.4 - { - finder.SetLimitsCount(static_cast<uint64_t>(tmp)); - } - } - - if (request.isMember(KEY_SINCE)) - { - int64_t tmp = request[KEY_SINCE].asInt64(); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_SINCE) + "\" must be a positive integer"); - } - else - { - finder.SetLimitsSince(static_cast<uint64_t>(tmp)); - } - } - - { + ResourceFinder finder(level, responseContent, context.GetFindStorageAccessMode(), context.GetIndex().HasFindSupport()); + + DatabaseLookup dicomTagLookup; + + { // common query code bool caseSensitive = false; if (request.isMember(KEY_CASE_SENSITIVE)) { caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); + + if (requestType == FindType_Count && caseSensitive) + { + /** + * Explanation: "/tools/find" uses "lookup_->IsMatch(tags)" in "ResourceFinder::Execute()" + * to apply case sensitiveness (as the database stores tags with PN VR in lower case). + * But, the purpose of "/tools/count-resources" is to speed up the counting the number of + * matching resources: Calling "lookup_->IsMatch(tags)" would require gathering the main + * DICOM tags, which would lead to no speedup wrt. "/tools/find". + **/ + throw OrthancException(ErrorCode_ParameterOutOfRange, "Setting \"" + std::string(KEY_CASE_SENSITIVE) + + "\" to \"true\" is not supported by /tools/count-resources"); + } } { // DICOM Tag query - DatabaseLookup dicomTagLookup; Json::Value::Members members = request[KEY_QUERY].getMemberNames(); for (size_t i = 0; i < members.size(); i++) @@ -3504,17 +3330,17 @@ } { // Metadata query - Json::Value::Members members = request[KEY_QUERY_METADATA].getMemberNames(); + Json::Value::Members members = request[KEY_METADATA_QUERY].getMemberNames(); for (size_t i = 0; i < members.size(); i++) { - if (request[KEY_QUERY_METADATA][members[i]].type() != Json::stringValue) + if (request[KEY_METADATA_QUERY][members[i]].type() != Json::stringValue) { throw OrthancException(ErrorCode_BadRequest, "Tag \"" + members[i] + "\" must be associated with a string"); } MetadataType metadata = StringToMetadata(members[i]); - const std::string value = request[KEY_QUERY_METADATA][members[i]].asString(); + const std::string value = request[KEY_METADATA_QUERY][members[i]].asString(); if (!value.empty()) { @@ -3536,251 +3362,213 @@ } } } - } - - if (request.isMember(KEY_REQUESTED_TAGS)) - { - std::set<DicomTag> requestedTags; - FromDcmtkBridge::ParseListOfTags(requestedTags, request[KEY_REQUESTED_TAGS]); - finder.AddRequestedTags(requestedTags); - } - - if (request.isMember(KEY_LABELS)) // New in Orthanc 1.12.0 - { - for (Json::Value::ArrayIndex i = 0; i < request[KEY_LABELS].size(); i++) - { - if (request[KEY_LABELS][i].type() != Json::stringValue) + + { // labels query + if (request.isMember(KEY_LABELS)) // New in Orthanc 1.12.0 { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS) + "\" must contain strings"); - } - else - { - finder.AddLabel(request[KEY_LABELS][i].asString()); + for (Json::Value::ArrayIndex i = 0; i < request[KEY_LABELS].size(); i++) + { + if (request[KEY_LABELS][i].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS) + "\" must contain strings"); + } + else + { + finder.AddLabel(request[KEY_LABELS][i].asString()); + } + } } - } - } - - finder.SetLabelsConstraint(LabelsConstraint_All); - - if (request.isMember(KEY_LABELS_CONSTRAINT)) - { - const std::string& s = request[KEY_LABELS_CONSTRAINT].asString(); - if (s == "All") - { + finder.SetLabelsConstraint(LabelsConstraint_All); - } - else if (s == "Any") - { - finder.SetLabelsConstraint(LabelsConstraint_Any); - } - else if (s == "None") - { - finder.SetLabelsConstraint(LabelsConstraint_None); - } - else - { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be \"All\", \"Any\", or \"None\""); - } - } - - if (request.isMember(KEY_PARENT_PATIENT)) // New in Orthanc 1.12.5 - { - finder.SetOrthancId(ResourceType_Patient, request[KEY_PARENT_PATIENT].asString()); - } - else if (request.isMember(KEY_PARENT_STUDY)) - { - finder.SetOrthancId(ResourceType_Study, request[KEY_PARENT_STUDY].asString()); - } - else if (request.isMember(KEY_PARENT_SERIES)) - { - finder.SetOrthancId(ResourceType_Series, request[KEY_PARENT_SERIES].asString()); - } - - if (request.isMember(KEY_ORDER_BY)) // New in Orthanc 1.12.5 - { - for (Json::Value::ArrayIndex i = 0; i < request[KEY_ORDER_BY].size(); i++) - { - if (request[KEY_ORDER_BY][i].type() != Json::objectValue) + + if (request.isMember(KEY_LABELS_CONSTRAINT)) { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY) + "\" must contain objects"); - } - else - { - const Json::Value& order = request[KEY_ORDER_BY][i]; - FindRequest::OrderingDirection direction; - std::string directionString; - std::string typeString; - - if (!order.isMember(KEY_ORDER_BY_KEY) || order[KEY_ORDER_BY_KEY].type() != Json::stringValue) + const std::string& s = request[KEY_LABELS_CONSTRAINT].asString(); + if (s == "All") { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_KEY) + "\" must be a string"); + finder.SetLabelsConstraint(LabelsConstraint_All); } - - if (!order.isMember(KEY_ORDER_BY_DIRECTION) || order[KEY_ORDER_BY_DIRECTION].type() != Json::stringValue) + else if (s == "Any") { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_DIRECTION) + "\" must be \"ASC\" or \"DESC\""); + finder.SetLabelsConstraint(LabelsConstraint_Any); } - - Toolbox::ToLowerCase(directionString, order[KEY_ORDER_BY_DIRECTION].asString()); - if (directionString == "asc") + else if (s == "None") { - direction = FindRequest::OrderingDirection_Ascending; - } - else if (directionString == "desc") - { - direction = FindRequest::OrderingDirection_Descending; + finder.SetLabelsConstraint(LabelsConstraint_None); } else { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_DIRECTION) + "\" must be \"ASC\" or \"DESC\""); - } - - if (!order.isMember(KEY_ORDER_BY_TYPE) || order[KEY_ORDER_BY_TYPE].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_TYPE) + "\" must be \"DicomTag\" or \"Metadata\""); - } - - Toolbox::ToLowerCase(typeString, order[KEY_ORDER_BY_TYPE].asString()); - if (typeString == "dicomtag") - { - DicomTag tag = FromDcmtkBridge::ParseTag(order[KEY_ORDER_BY_KEY].asString()); - finder.AddOrdering(tag, direction); - } - else if (typeString == "metadata") - { - MetadataType metadata = StringToMetadata(order[KEY_ORDER_BY_KEY].asString()); - finder.AddOrdering(metadata, direction); - } - else - { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_TYPE) + "\" must be \"DicomTag\" or \"Metadata\""); + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be \"All\", \"Any\", or \"None\""); } } } - } - - Json::Value answer; - finder.Execute(answer, context, format, false /* no "Metadata" field */); - call.GetOutput().AnswerJson(answer); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - bool expand = false; - if (request.isMember(KEY_EXPAND)) - { - expand = request[KEY_EXPAND].asBool(); - } - - bool caseSensitive = false; - if (request.isMember(KEY_CASE_SENSITIVE)) - { - caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); - } - - size_t limit = 0; - if (request.isMember(KEY_LIMIT)) - { - int tmp = request[KEY_LIMIT].asInt(); - if (tmp < 0) + + // parents query + if (request.isMember(KEY_PARENT_PATIENT)) // New in Orthanc 1.12.5 { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_LIMIT) + "\" must be a positive integer"); + finder.SetOrthancId(ResourceType_Patient, request[KEY_PARENT_PATIENT].asString()); } - - limit = static_cast<size_t>(tmp); - } - - size_t since = 0; - if (request.isMember(KEY_SINCE)) - { - int tmp = request[KEY_SINCE].asInt(); - if (tmp < 0) + else if (request.isMember(KEY_PARENT_STUDY)) { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_SINCE) + "\" must be a positive integer"); + finder.SetOrthancId(ResourceType_Study, request[KEY_PARENT_STUDY].asString()); } - - since = static_cast<size_t>(tmp); - } - - std::set<DicomTag> requestedTags; - - if (request.isMember(KEY_REQUESTED_TAGS)) - { - FromDcmtkBridge::ParseListOfTags(requestedTags, request[KEY_REQUESTED_TAGS]); - } - - ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); - - DatabaseLookup query; - - Json::Value::Members members = request[KEY_QUERY].getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - if (request[KEY_QUERY][members[i]].type() != Json::stringValue) + else if (request.isMember(KEY_PARENT_SERIES)) { - throw OrthancException(ErrorCode_BadRequest, - "Tag \"" + members[i] + "\" must be associated with a string"); - } - - const std::string value = request[KEY_QUERY][members[i]].asString(); - - if (!value.empty()) - { - // An empty string corresponds to an universal constraint, - // so we ignore it. This mimics the behavior of class - // "OrthancFindRequestHandler" - query.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), - value, caseSensitive, true); + finder.SetOrthancId(ResourceType_Series, request[KEY_PARENT_SERIES].asString()); } } - std::set<std::string> labels; - - if (request.isMember(KEY_LABELS)) // New in Orthanc 1.12.0 + // response + if (requestType == FindType_Find) { - for (Json::Value::ArrayIndex i = 0; i < request[KEY_LABELS].size(); i++) + const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human); + + finder.SetDatabaseLimits(context.GetDatabaseLimits(level)); + + if ((request.isMember(KEY_SINCE) && request[KEY_SINCE].asInt64() != 0) && + !finder.CanBeFullyPerformedInDb()) + { + throw OrthancException(ErrorCode_BadRequest, + "Unable to use '" + std::string(KEY_SINCE) + "' in tools/find when querying tags that are not stored as MainDicomTags in the Database"); + } + + if (request.isMember(KEY_LIMIT)) { - if (request[KEY_LABELS][i].type() != Json::stringValue) + int64_t tmp = request[KEY_LIMIT].asInt64(); + if (tmp < 0) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Field \"" + std::string(KEY_LIMIT) + "\" must be a positive integer"); + } + else if (tmp != 0) // This is for compatibility with Orthanc 1.12.4 { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS) + "\" must contain strings"); + finder.SetLimitsCount(static_cast<uint64_t>(tmp)); + } + } + + if (request.isMember(KEY_SINCE)) + { + int64_t tmp = request[KEY_SINCE].asInt64(); + if (tmp < 0) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Field \"" + std::string(KEY_SINCE) + "\" must be a positive integer"); } else { - labels.insert(request[KEY_LABELS][i].asString()); + finder.SetLimitsSince(static_cast<uint64_t>(tmp)); } } - } - - LabelsConstraint labelsConstraint = LabelsConstraint_All; - - if (request.isMember(KEY_LABELS_CONSTRAINT)) - { - const std::string& s = request[KEY_LABELS_CONSTRAINT].asString(); - if (s == "All") + + if (request.isMember(KEY_REQUESTED_TAGS)) { - labelsConstraint = LabelsConstraint_All; + std::set<DicomTag> requestedTags; + FromDcmtkBridge::ParseListOfTags(requestedTags, request[KEY_REQUESTED_TAGS]); + finder.AddRequestedTags(requestedTags); } - else if (s == "Any") + + if (request.isMember(KEY_ORDER_BY)) // New in Orthanc 1.12.5 { - labelsConstraint = LabelsConstraint_Any; - } - else if (s == "None") - { - labelsConstraint = LabelsConstraint_None; + for (Json::Value::ArrayIndex i = 0; i < request[KEY_ORDER_BY].size(); i++) + { + if (request[KEY_ORDER_BY][i].type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY) + "\" must contain objects"); + } + else + { + const Json::Value& order = request[KEY_ORDER_BY][i]; + FindRequest::OrderingDirection direction; + std::string directionString; + std::string typeString; + + if (!order.isMember(KEY_ORDER_BY_KEY) || order[KEY_ORDER_BY_KEY].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_KEY) + "\" must be a string"); + } + + if (!order.isMember(KEY_ORDER_BY_DIRECTION) || order[KEY_ORDER_BY_DIRECTION].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_DIRECTION) + "\" must be \"ASC\" or \"DESC\""); + } + + Toolbox::ToLowerCase(directionString, order[KEY_ORDER_BY_DIRECTION].asString()); + if (directionString == "asc") + { + direction = FindRequest::OrderingDirection_Ascending; + } + else if (directionString == "desc") + { + direction = FindRequest::OrderingDirection_Descending; + } + else + { + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_DIRECTION) + "\" must be \"ASC\" or \"DESC\""); + } + + if (!order.isMember(KEY_ORDER_BY_TYPE) || order[KEY_ORDER_BY_TYPE].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_TYPE) + "\" must be \"DicomTag\" or \"Metadata\""); + } + + Toolbox::ToLowerCase(typeString, order[KEY_ORDER_BY_TYPE].asString()); + if (Toolbox::StartsWith(typeString, "dicomtag")) + { + DicomTag tag = FromDcmtkBridge::ParseTag(order[KEY_ORDER_BY_KEY].asString()); + + if (typeString == "dicomtagasint") + { + finder.AddOrdering(tag, FindRequest::OrderingCast_Int, direction); + } + else if (typeString == "dicomtagasfloat") + { + finder.AddOrdering(tag, FindRequest::OrderingCast_Float, direction); + } + else + { + finder.AddOrdering(tag, FindRequest::OrderingCast_String, direction); + } + } + else if (Toolbox::StartsWith(typeString, "metadata")) + { + MetadataType metadata = StringToMetadata(order[KEY_ORDER_BY_KEY].asString()); + + if (typeString == "metadataasint") + { + finder.AddOrdering(metadata, FindRequest::OrderingCast_Int, direction); + } + else if (typeString == "dicomtagasfloat") + { + finder.AddOrdering(metadata, FindRequest::OrderingCast_Float, direction); + } + else + { + finder.AddOrdering(metadata, FindRequest::OrderingCast_String, direction); + } + } + else + { + throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY_TYPE) + "\" must be \"DicomTag\", \"DicomTagAsInt\", \"DicomTagAsFloat\" or \"Metadata\", \"MetadataAsInt\", \"MetadataAsFloat\""); + } + } + } } - else - { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be \"All\", \"Any\", or \"None\""); - } + + Json::Value answer; + finder.Execute(answer, context, format, false /* no "Metadata" field */); + call.GetOutput().AnswerJson(answer); } - - FindVisitor visitor(OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human), context.GetFindStorageAccessMode()); - context.Apply(visitor, query, level, labels, labelsConstraint, since, limit); - visitor.Answer(call.GetOutput(), context, level, expand, requestedTags); + else if (requestType == FindType_Count) + { + uint64_t count = finder.Count(context); + Json::Value answer; + answer["Count"] = Json::Value::UInt64(count); + call.GetOutput().AnswerJson(answer); + } + else + { + throw OrthancException(ErrorCode_InternalError); + } } } @@ -3809,9 +3597,6 @@ return; } - ServerIndex& index = OrthancRestApi::GetIndex(call); - ServerContext& context = OrthancRestApi::GetContext(call); - const bool expand = (!call.HasArgument("expand") || // this "expand" is the only one to have a false default value to keep backward compatibility call.GetBooleanArgument("expand", false)); @@ -3820,61 +3605,30 @@ std::set<DicomTag> requestedTags; OrthancRestApi::GetRequestedTags(requestedTags, call); - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(end, (expand ? ResponseContentFlags_ExpandTrue : ResponseContentFlags_ID)); - finder.SetOrthancId(start, call.GetUriComponent("id", "")); - finder.AddRequestedTags(requestedTags); - - Json::Value answer; - finder.Execute(answer, context, format, false /* no "Metadata" field */); - call.GetOutput().AnswerJson(answer); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - std::list<std::string> a, b, c; - a.push_back(call.GetUriComponent("id", "")); - - ResourceType type = start; - while (type != end) - { - b.clear(); - - for (std::list<std::string>::const_iterator - it = a.begin(); it != a.end(); ++it) - { - index.GetChildren(c, *it); - b.splice(b.begin(), c); - } - - type = GetChildResourceType(type); - - a.clear(); - a.splice(a.begin(), b); - } - - AnswerListOfResources2(call.GetOutput(), context, a, type, expand, format, requestedTags, true /* allowStorageAccess */); - } + ResourceFinder finder(end, + (expand ? ResponseContentFlags_ExpandTrue : ResponseContentFlags_ID), + OrthancRestApi::GetContext(call).GetFindStorageAccessMode(), + OrthancRestApi::GetContext(call).GetIndex().HasFindSupport()); + finder.SetOrthancId(start, call.GetUriComponent("id", "")); + finder.AddRequestedTags(requestedTags); + + Json::Value answer; + finder.Execute(answer, OrthancRestApi::GetContext(call), format, false /* no "Metadata" field */); + call.GetOutput().AnswerJson(answer); } static void GetChildInstancesTags(RestApiGetCall& call) { + const ResourceType level = GetResourceTypeFromUri(call); + if (call.IsDocumentation()) { OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full); - ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str()); - std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */); + std::string r = GetResourceTypeText(level, false /* plural */, false /* upper case */); call.GetDocumentation() - .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */)) + .SetTag(GetResourceTypeText(level, true /* plural */, true /* upper case */)) .SetSummary("Get tags of instances") .SetDescription("Get the tags of all the child instances of the DICOM " + r + " whose Orthanc identifier is provided in the URL") @@ -3882,7 +3636,7 @@ .SetHttpGetArgument(IGNORE_LENGTH, RestApiCallDocumentation::Type_JsonListOfStrings, "Also include the DICOM tags that are provided in this list, even if their associated value is long", false) .AddAnswerType(MimeType_Json, "JSON object associating the Orthanc identifiers of the instances, with the values of their DICOM tags") - .SetTruncatedJsonHttpGetSample(GetDocumentationSampleResource(t) + "/instances-tags", 5); + .SetTruncatedJsonHttpGetSample(GetDocumentationSampleResource(level) + "/instances-tags", 5); return; } @@ -3897,7 +3651,7 @@ typedef std::list<std::string> Instances; Instances instances; - context.GetIndex().GetChildInstances(instances, publicId); // (*) + context.GetIndex().GetChildInstances(instances, publicId, level); // (*) Json::Value result = Json::objectValue; @@ -3974,26 +3728,9 @@ const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); Json::Value resource; - - if (true) + if (ExpandResource(resource, OrthancRestApi::GetContext(call), currentType, current, format, false)) { - /** - * EXPERIMENTAL VERSION - **/ - if (ExpandResource(resource, OrthancRestApi::GetContext(call), currentType, current, format, false)) - { - call.GetOutput().AnswerJson(resource); - } - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - if (OrthancRestApi::GetContext(call).ExpandResource(resource, current, end, format, requestedTags, true /* allowStorageAccess */)) - { - call.GetOutput().AnswerJson(resource); - } + call.GetOutput().AnswerJson(resource); } } @@ -4120,7 +3857,7 @@ study = studies.begin(); study != studies.end(); ++study) { std::list<std::string> instances; - index.GetChildInstances(instances, *study); + index.GetChildInstances(instances, *study, ResourceType_Study); for (std::list<std::string>::const_iterator instance = instances.begin(); instance != instances.end(); ++instance) @@ -4251,6 +3988,7 @@ static void GetBulkChildren(std::set<std::string>& target, ServerIndex& index, + ResourceType level, const std::set<std::string>& source) { target.clear(); @@ -4259,7 +3997,7 @@ it = source.begin(); it != source.end(); ++it) { std::list<std::string> children; - index.GetChildren(children, *it); + index.GetChildren(children, level, *it); for (std::list<std::string>::const_iterator child = children.begin(); child != children.end(); ++child) @@ -4270,24 +4008,6 @@ } - static void AddMetadata(Json::Value& target, - ServerIndex& index, - const std::string& resource, - ResourceType level) - { - target = Json::objectValue; - - std::map<MetadataType, std::string> content; - index.GetAllMetadata(content, resource, level); - - for (std::map<MetadataType, std::string>::const_iterator - it = content.begin(); it != content.end(); ++it) - { - target[EnumerationToString(it->first)] = it->second; - } - } - - static void BulkContent(RestApiPostCall& call) { static const char* const LEVEL = "Level"; @@ -4364,11 +4084,11 @@ // Need to explore children std::set<std::string> current; current.insert(*it); - + for (;;) { std::set<std::string> children; - GetBulkChildren(children, index, current); + GetBulkChildren(children, index, type, current); type = GetChildResourceType(type); if (type == level) @@ -4424,34 +4144,10 @@ for (std::set<std::string>::const_iterator it = interest.begin(); it != interest.end(); ++it) { - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - Json::Value item; - if (ExpandResource(item, OrthancRestApi::GetContext(call), level, *it, format, metadata)) - { - answer.append(item); - } - } - else + Json::Value item; + if (ExpandResource(item, OrthancRestApi::GetContext(call), level, *it, format, metadata)) { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - Json::Value item; - std::set<DicomTag> emptyRequestedTags; // not supported for bulk content - - if (OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) - { - if (metadata) - { - AddMetadata(item[METADATA], index, *it, level); - } - - answer.append(item); - } + answer.append(item); } } } @@ -4466,38 +4162,15 @@ { ResourceType level; Json::Value item; - std::set<DicomTag> emptyRequestedTags; // not supported for bulk content - - if (true) + + if (index.LookupResourceType(level, *it) && + ExpandResource(item, OrthancRestApi::GetContext(call), level, *it, format, metadata)) { - /** - * EXPERIMENTAL VERSION - **/ - if (index.LookupResourceType(level, *it) && - ExpandResource(item, OrthancRestApi::GetContext(call), level, *it, format, metadata)) - { - answer.append(item); - } + answer.append(item); } else { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - if (index.LookupResourceType(level, *it) && - OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) - { - if (metadata) - { - AddMetadata(item[METADATA], index, *it, level); - } - - answer.append(item); - } - else - { - CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it; - } + CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it; } } } @@ -4688,7 +4361,8 @@ } Register("/tools/lookup", Lookup); - Register("/tools/find", Find); + Register("/tools/find", Find<FindType_Find>); + Register("/tools/count-resources", Find<FindType_Count>); Register("/patients/{id}/studies", GetChildResources<ResourceType_Patient, ResourceType_Study>); Register("/patients/{id}/series", GetChildResources<ResourceType_Patient, ResourceType_Series>);
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -75,6 +75,7 @@ static const char* const DATABASE_BACKEND_PLUGIN = "DatabaseBackendPlugin"; static const char* const DATABASE_VERSION = "DatabaseVersion"; static const char* const DATABASE_SERVER_IDENTIFIER = "DatabaseServerIdentifier"; + static const char* const DEFAULT_RETRIEVE_METHOD = "DefaultRetrieveMethod"; static const char* const DICOM_AET = "DicomAet"; static const char* const DICOM_PORT = "DicomPort"; static const char* const HTTP_PORT = "HttpPort"; @@ -115,6 +116,7 @@ "Information about the installed storage area plugin (`null` if no such plugin is installed)") .SetAnswerField(DATABASE_BACKEND_PLUGIN, RestApiCallDocumentation::Type_String, "Information about the installed database index plugin (`null` if no such plugin is installed)") + .SetAnswerField(DEFAULT_RETRIEVE_METHOD, RestApiCallDocumentation::Type_String, "The DefaultRetrieveMethod configuration") .SetAnswerField(DICOM_AET, RestApiCallDocumentation::Type_String, "The DICOM AET of Orthanc") .SetAnswerField(DICOM_PORT, RestApiCallDocumentation::Type_Number, "The port to the DICOM server of Orthanc") .SetAnswerField(HTTP_PORT, RestApiCallDocumentation::Type_Number, "The port to the HTTP server of Orthanc") @@ -173,6 +175,7 @@ result[MAXIMUM_STORAGE_SIZE] = lock.GetConfiguration().GetUnsignedIntegerParameter(MAXIMUM_STORAGE_SIZE, 0); // New in Orthanc 1.11.3 result[MAXIMUM_PATIENT_COUNT] = lock.GetConfiguration().GetUnsignedIntegerParameter(MAXIMUM_PATIENT_COUNT, 0); // New in Orthanc 1.12.4 result[MAXIMUM_STORAGE_MODE] = lock.GetConfiguration().GetStringParameter(MAXIMUM_STORAGE_MODE, "Recycle"); // New in Orthanc 1.11.3 + result[DEFAULT_RETRIEVE_METHOD] = lock.GetConfiguration().GetStringParameter(DEFAULT_RETRIEVE_METHOD, "C-MOVE"); } result[STORAGE_AREA_PLUGIN] = Json::nullValue; @@ -478,6 +481,33 @@ AnswerAcceptedTransferSyntaxes(call); } + static void GetAcceptedSopClasses(RestApiGetCall& call) + { + if (call.IsDocumentation()) + { + call.GetDocumentation() + .SetTag("System") + .SetSummary("Get accepted SOPClassUID") + .SetDescription("Get the list of SOP Class UIDs that are accepted " + "by Orthanc C-STORE SCP. This corresponds to the configuration options " + "`AcceptedSopClasses` and `RejectedSopClasses`.") + .AddAnswerType(MimeType_Json, "JSON array containing the SOP Class UIDs"); + return; + } + + std::set<std::string> sopClasses; + OrthancRestApi::GetContext(call).GetAcceptedSopClasses(sopClasses, 0); + + Json::Value json = Json::arrayValue; + for (std::set<std::string>::const_iterator + sop = sopClasses.begin(); sop != sopClasses.end(); ++sop) + { + json.append(*sop); + } + + call.GetOutput().AnswerJson(json); + } + static void GetUnknownSopClassAccepted(RestApiGetCall& call) { @@ -1200,5 +1230,8 @@ Register("/tools/unknown-sop-class-accepted", SetUnknownSopClassAccepted); Register("/tools/labels", ListAllLabels); // New in Orthanc 1.12.0 + + Register("/tools/accepted-sop-classes", GetAcceptedSopClasses); + } }
--- a/OrthancServer/Sources/OrthancWebDav.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancWebDav.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -74,8 +74,7 @@ MetadataType metadata) { std::string value; - int64_t revision; // Ignored - if (context.GetIndex().LookupMetadata(value, revision, publicId, level, metadata)) + if (context.GetIndex().LookupMetadata(value, publicId, level, metadata)) { ParseTime(target, value); } @@ -86,99 +85,6 @@ } - class OrthancWebDav::DicomIdentifiersVisitor : public ServerContext::ILookupVisitor - { - private: - ServerContext& context_; - bool isComplete_; - Collection& target_; - ResourceType level_; - - public: - DicomIdentifiersVisitor(ServerContext& context, - Collection& target, - ResourceType level) : - context_(context), - isComplete_(false), - target_(target), - level_(level) - { - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - isComplete_ = true; // TODO - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId /* unused */, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE - { - DicomTag tag(0, 0); - MetadataType timeMetadata; - - switch (level_) - { - case ResourceType_Study: - tag = DICOM_TAG_STUDY_INSTANCE_UID; - timeMetadata = MetadataType_LastUpdate; - break; - - case ResourceType_Series: - tag = DICOM_TAG_SERIES_INSTANCE_UID; - timeMetadata = MetadataType_LastUpdate; - break; - - case ResourceType_Instance: - tag = DICOM_TAG_SOP_INSTANCE_UID; - timeMetadata = MetadataType_Instance_ReceptionDate; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - std::string s; - if (mainDicomTags.LookupStringValue(s, tag, false) && - !s.empty()) - { - std::unique_ptr<Resource> resource; - - if (level_ == ResourceType_Instance) - { - FileInfo info; - int64_t revision; // Ignored - if (context_.GetIndex().LookupAttachment(info, revision, publicId, FileContentType_Dicom)) - { - std::unique_ptr<File> f(new File(s + ".dcm")); - f->SetMimeType(MimeType_Dicom); - f->SetContentLength(info.GetUncompressedSize()); - resource.reset(f.release()); - } - } - else - { - resource.reset(new Folder(s)); - } - - if (resource.get() != NULL) - { - boost::posix_time::ptime t; - LookupTime(t, context_, publicId, level_, timeMetadata); - resource->SetCreationTime(t); - target_.AddResource(resource.release()); - } - } - } - }; - - class OrthancWebDav::DicomIdentifiersVisitorV2 : public ResourceFinder::IVisitor { private: @@ -238,7 +144,8 @@ if (resource.GetLevel() == ResourceType_Instance) { FileInfo info; - if (resource.LookupAttachment(info, FileContentType_Dicom)) + int64_t revision; + if (resource.LookupAttachment(info, revision, FileContentType_Dicom)) { std::unique_ptr<File> f(new File(uid + ".dcm")); f->SetMimeType(MimeType_Dicom); @@ -271,58 +178,6 @@ }; - class OrthancWebDav::DicomFileVisitor : public ServerContext::ILookupVisitor - { - private: - ServerContext& context_; - bool success_; - std::string& target_; - boost::posix_time::ptime& time_; - - public: - DicomFileVisitor(ServerContext& context, - std::string& target, - boost::posix_time::ptime& time) : - context_(context), - success_(false), - target_(target), - time_(time) - { - } - - bool IsSuccess() const - { - return success_; - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId /* unused */, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE - { - if (success_) - { - success_ = false; // Two matches => Error - } - else - { - LookupTime(time_, context_, publicId, ResourceType_Instance, MetadataType_Instance_ReceptionDate); - context_.ReadDicom(target_, publicId); - success_ = true; - } - } - }; - - class OrthancWebDav::DicomFileVisitorV2 : public ResourceFinder::IVisitor { private: @@ -377,67 +232,6 @@ }; - class OrthancWebDav::OrthancJsonVisitor : public ServerContext::ILookupVisitor - { - private: - ServerContext& context_; - bool success_; - std::string& target_; - ResourceType level_; - - public: - OrthancJsonVisitor(ServerContext& context, - std::string& target, - ResourceType level) : - context_(context), - success_(false), - target_(target), - level_(level) - { - } - - bool IsSuccess() const - { - return success_; - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId /* unused */, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE - { - Json::Value resource; - std::set<DicomTag> emptyRequestedTags; // not supported for webdav - - if (context_.ExpandResource(resource, publicId, level_, DicomToJsonFormat_Human, emptyRequestedTags, true /* allowStorageAccess */)) - { - if (success_) - { - success_ = false; // Two matches => Error - } - else - { - target_ = resource.toStyledString(); - - // Replace UNIX newlines with DOS newlines - boost::replace_all(target_, "\n", "\r\n"); - - success_ = true; - } - } - } - }; - - class OrthancWebDav::ResourcesIndex : public boost::noncopyable { public: @@ -642,7 +436,7 @@ std::list<std::string> resources; try { - context_.GetIndex().GetChildren(resources, parentSeries_); + context_.GetIndex().GetChildren(resources, ResourceType_Series, parentSeries_); } catch (OrthancException&) { @@ -658,7 +452,7 @@ FileInfo info; int64_t revision; // Ignored - if (context_.GetIndex().LookupAttachment(info, revision, *it, FileContentType_Dicom)) + if (context_.GetIndex().LookupAttachment(info, revision, ResourceType_Instance, *it, FileContentType_Dicom)) { std::unique_ptr<File> resource(new File(*it + ".dcm")); resource->SetMimeType(MimeType_Dicom); @@ -711,7 +505,7 @@ std::list<std::string> resources; try { - context_.GetIndex().GetChildren(resources, parentSeries_); + context_.GetIndex().GetChildren(resources, ResourceType_Series, parentSeries_); } catch (OrthancException&) { @@ -1029,6 +823,7 @@ class OrthancWebDav::SingleDicomResource : public ListOfResources { private: + ResourceType parentLevel_; std::string parentId_; protected: @@ -1036,7 +831,7 @@ { try { - GetContext().GetIndex().GetChildren(resources, parentId_); + GetContext().GetIndex().GetChildren(resources, parentLevel_, parentId_); } catch (OrthancException&) { @@ -1068,6 +863,7 @@ const std::string& parentId, const Templates& templates) : ListOfResources(context, level, templates), + parentLevel_(GetParentResourceType(level)), parentId_(parentId) { } @@ -1142,7 +938,7 @@ Visitor visitor(resources); - ResourceFinder finder(ResourceType_Study, ResponseContentFlags_ID); + ResourceFinder finder(ResourceType_Study, ResponseContentFlags_ID, GetContext().GetFindStorageAccessMode(), GetContext().GetIndex().HasFindSupport()); finder.SetDatabaseLookup(query); finder.Execute(visitor, GetContext()); } @@ -1220,7 +1016,7 @@ Visitor visitor; - ResourceFinder finder(ResourceType_Study, ResponseContentFlags_ID); + ResourceFinder finder(ResourceType_Study, ResponseContentFlags_ID, context_.GetFindStorageAccessMode(), context_.GetIndex().HasFindSupport()); finder.SetDatabaseLookup(query); finder.Execute(visitor, context_); @@ -1569,12 +1365,11 @@ { DatabaseLookup query; ResourceType level; - size_t limit = 0; // By default, no limits if (path.size() == 1) { level = ResourceType_Study; - limit = 0; // TODO - Should we limit here? + // TODO - Should we limit here? } else if (path.size() == 2) { @@ -1599,47 +1394,31 @@ return false; } - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(level, ResponseContentFlags_ID); - finder.SetDatabaseLookup(query); - finder.SetRetrieveMetadata(true); + ResourceFinder finder(level, ResponseContentFlags_ID, context_.GetFindStorageAccessMode(), context_.GetIndex().HasFindSupport()); + finder.SetDatabaseLookup(query); + finder.SetRetrieveMetadata(true); - switch (level) - { - case ResourceType_Study: - finder.AddRequestedTag(DICOM_TAG_STUDY_INSTANCE_UID); - break; - - case ResourceType_Series: - finder.AddRequestedTag(DICOM_TAG_SERIES_INSTANCE_UID); - break; + switch (level) + { + case ResourceType_Study: + finder.AddRequestedTag(DICOM_TAG_STUDY_INSTANCE_UID); + break; - case ResourceType_Instance: - finder.AddRequestedTag(DICOM_TAG_SOP_INSTANCE_UID); - finder.SetRetrieveAttachments(true); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } + case ResourceType_Series: + finder.AddRequestedTag(DICOM_TAG_SERIES_INSTANCE_UID); + break; - DicomIdentifiersVisitorV2 visitor(collection); - finder.Execute(visitor, context_); + case ResourceType_Instance: + finder.AddRequestedTag(DICOM_TAG_SOP_INSTANCE_UID); + finder.SetRetrieveAttachments(true); + break; + + default: + throw OrthancException(ErrorCode_InternalError); } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - DicomIdentifiersVisitor visitor(context_, collection, level); - context_.Apply(visitor, query, level, 0 /* since */, limit); - } + DicomIdentifiersVisitorV2 visitor(collection); + finder.Execute(visitor, context_); return true; } @@ -1666,7 +1445,7 @@ ResourceType level, const DatabaseLookup& query) { - ResourceFinder finder(level, ResponseContentFlags_ExpandTrue); + ResourceFinder finder(level, ResponseContentFlags_ExpandTrue, context.GetFindStorageAccessMode(), context.GetIndex().HasFindSupport()); finder.SetDatabaseLookup(query); Json::Value expanded; @@ -1707,23 +1486,7 @@ true /* case sensitive */, true /* mandatory tag */); mime = MimeType_Json; - - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - return GetOrthancJson(content, context_, ResourceType_Study, query); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - OrthancJsonVisitor visitor(context_, content, ResourceType_Study); - context_.Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */); - return visitor.IsSuccess(); - } + return GetOrthancJson(content, context_, ResourceType_Study, query); } else if (path.size() == 4 && path[3] == SERIES_INFO) @@ -1735,23 +1498,7 @@ true /* case sensitive */, true /* mandatory tag */); mime = MimeType_Json; - - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - return GetOrthancJson(content, context_, ResourceType_Series, query); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - OrthancJsonVisitor visitor(context_, content, ResourceType_Series); - context_.Apply(visitor, query, ResourceType_Series, 0 /* since */, 0 /* no limit */); - return visitor.IsSuccess(); - } + return GetOrthancJson(content, context_, ResourceType_Series, query); } else if (path.size() == 4 && boost::ends_with(path[3], ".dcm")) @@ -1768,30 +1515,15 @@ mime = MimeType_Dicom; - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - ResourceFinder finder(ResourceType_Instance, ResponseContentFlags_ID); - finder.SetDatabaseLookup(query); - finder.SetRetrieveMetadata(true); - finder.SetRetrieveAttachments(true); + ResourceFinder finder(ResourceType_Instance, ResponseContentFlags_ID, context_.GetFindStorageAccessMode(), context_.GetIndex().HasFindSupport()); + finder.SetDatabaseLookup(query); + finder.SetRetrieveMetadata(true); + finder.SetRetrieveAttachments(true); - DicomFileVisitorV2 visitor(context_, content, modificationTime); - finder.Execute(visitor, context_); + DicomFileVisitorV2 visitor(context_, content, modificationTime); + finder.Execute(visitor, context_); - return visitor.IsSuccess(); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - DicomFileVisitor visitor(context_, content, modificationTime); - context_.Apply(visitor, query, ResourceType_Instance, 0 /* since */, 0 /* no limit */); - return visitor.IsSuccess(); - } + return visitor.IsSuccess(); } else { @@ -1913,7 +1645,7 @@ DicomDeleteVisitor visitor(context_, level); - ResourceFinder finder(level, ResponseContentFlags_ID); + ResourceFinder finder(level, ResponseContentFlags_ID, context_.GetFindStorageAccessMode(), context_.GetIndex().HasFindSupport()); finder.SetDatabaseLookup(query); finder.Execute(visitor, context_); return true;
--- a/OrthancServer/Sources/OrthancWebDav.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/OrthancWebDav.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -38,9 +38,7 @@ typedef std::map<ResourceType, std::string> Templates; class DicomDeleteVisitor; - class DicomFileVisitor; class DicomFileVisitorV2; - class DicomIdentifiersVisitor; class DicomIdentifiersVisitorV2; class InstancesOfSeries; class InternalNode;
--- a/OrthancServer/Sources/PrecompiledHeadersServer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/PrecompiledHeadersServer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/PrecompiledHeadersServer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/PrecompiledHeadersServer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/QueryRetrieveHandler.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/QueryRetrieveHandler.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -79,7 +79,7 @@ params.SetTimeout(timeout_); } - DicomControlUserConnection connection(params); + DicomControlUserConnection connection(params, static_cast<ScuOperationFlags>(ScuOperationFlags_Find)); connection.Find(answers_, level_, fixed, findNormalized_); }
--- a/OrthancServer/Sources/QueryRetrieveHandler.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/QueryRetrieveHandler.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ResourceFinder.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ResourceFinder.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -56,7 +56,7 @@ if (request_.GetLevel() == parentLevel) { requestedComputedTags_.insert(tag); - request_.GetChildrenSpecification(childLevel).SetRetrieveIdentifiers(true); + request_.GetChildrenSpecification(childLevel).SetRetrieveCount(true); } } @@ -68,8 +68,7 @@ { if (IsRequestedComputedTag(tag)) { - const std::set<std::string>& children = resource.GetChildrenIdentifiers(level); - requestedTags.SetValue(tag, boost::lexical_cast<std::string>(children.size()), false); + requestedTags.SetValue(tag, boost::lexical_cast<std::string>(resource.GetChildrenCount(level)), false); } } @@ -326,7 +325,8 @@ if (responseContent_ & ResponseContentFlags_AttachmentsLegacy) { FileInfo info; - if (resource.LookupAttachment(info, FileContentType_Dicom)) + int64_t revision; + if (resource.LookupAttachment(info, revision, FileContentType_Dicom)) { target["FileSize"] = static_cast<Json::UInt64>(info.GetUncompressedSize()); target["FileUuid"] = info.GetUuid(); @@ -438,13 +438,13 @@ if (responseContent_ & ResponseContentFlags_Metadata) // new in Orthanc 1.12.4 { - const std::map<MetadataType, std::string>& m = resource.GetMetadata(resource.GetLevel()); + const std::map<MetadataType, FindResponse::MetadataContent>& m = resource.GetMetadata(resource.GetLevel()); Json::Value metadata = Json::objectValue; - for (std::map<MetadataType, std::string>::const_iterator it = m.begin(); it != m.end(); ++it) + for (std::map<MetadataType, FindResponse::MetadataContent>::const_iterator it = m.begin(); it != m.end(); ++it) { - metadata[EnumerationToString(it->first)] = it->second; + metadata[EnumerationToString(it->first)] = it->second.GetValue(); } target["Metadata"] = metadata; @@ -472,66 +472,92 @@ } - void ResourceFinder::UpdateRequestLimits() + void ResourceFinder::UpdateRequestLimits(ServerContext& context) { - // By default, use manual paging - pagingMode_ = PagingMode_FullManual; + if (context.GetIndex().HasFindSupport()) // in this case, limits are fully implemented in DB + { + pagingMode_ = PagingMode_FullDatabase; - if (databaseLimits_ != 0) - { - request_.SetLimits(0, databaseLimits_ + 1); + if (hasLimitsSince_ || hasLimitsCount_) + { + pagingMode_ = PagingMode_FullDatabase; + if (databaseLimits_ != 0 && limitsCount_ > databaseLimits_) + { + LOG(WARNING) << "ResourceFinder: \"Limit\" is larger than LimitFindResults/LimitFindInstances configurations, using limit from the configuration file"; + limitsCount_ = databaseLimits_; + } + + request_.SetLimits(limitsSince_, limitsCount_); + } + else if (databaseLimits_ != 0) + { + request_.SetLimits(0, databaseLimits_); + } + } else { - request_.ClearLimits(); - } - - if (lookup_.get() == NULL && - (hasLimitsSince_ || hasLimitsCount_)) - { - pagingMode_ = PagingMode_FullDatabase; - request_.SetLimits(limitsSince_, limitsCount_); - } + // By default, use manual paging + pagingMode_ = PagingMode_FullManual; - if (lookup_.get() != NULL && - isSimpleLookup_ && - (hasLimitsSince_ || hasLimitsCount_)) - { - /** - * TODO-FIND: "IDatabaseWrapper::ApplyLookupResources()" only - * accept the "limit" argument. The "since" must be implemented - * manually. - **/ - - if (hasLimitsSince_ && - limitsSince_ != 0) + if (databaseLimits_ != 0) { - pagingMode_ = PagingMode_ManualSkip; - request_.SetLimits(0, limitsCount_ + limitsSince_); + request_.SetLimits(0, databaseLimits_ + 1); } else { + request_.ClearLimits(); + } + + if (lookup_.get() == NULL && + (hasLimitsSince_ || hasLimitsCount_)) + { pagingMode_ = PagingMode_FullDatabase; - request_.SetLimits(0, limitsCount_); + request_.SetLimits(limitsSince_, limitsCount_); + } + + if (lookup_.get() != NULL && + canBeFullyPerformedInDb_ && + (hasLimitsSince_ || hasLimitsCount_)) + { + /** + * TODO-FIND: "IDatabaseWrapper::ApplyLookupResources()" only + * accept the "limit" argument. The "since" must be implemented + * manually. + **/ + + if (hasLimitsSince_ && + limitsSince_ != 0) + { + pagingMode_ = PagingMode_ManualSkip; + request_.SetLimits(0, limitsCount_ + limitsSince_); + } + else + { + pagingMode_ = PagingMode_FullDatabase; + request_.SetLimits(0, limitsCount_); + } } } - - // TODO-FIND: More cases could be added, depending on "GetDatabaseCapabilities()" } ResourceFinder::ResourceFinder(ResourceType level, - ResponseContentFlags responseContent) : + ResponseContentFlags responseContent, + FindStorageAccessMode storageAccessMode, + bool supportsChildExistQueries) : request_(level), databaseLimits_(0), isSimpleLookup_(true), + canBeFullyPerformedInDb_(true), pagingMode_(PagingMode_FullManual), hasLimitsSince_(false), hasLimitsCount_(false), limitsSince_(0), limitsCount_(0), responseContent_(responseContent), - allowStorageAccess_(true), + storageAccessMode_(storageAccessMode), + supportsChildExistQueries_(supportsChildExistQueries), isWarning002Enabled_(false), isWarning004Enabled_(false), isWarning005Enabled_(false) @@ -543,8 +569,6 @@ isWarning005Enabled_ = lock.GetConfiguration().IsWarningEnabled(Warnings_005_RequestingTagFromLowerResourceLevel); } - UpdateRequestLimits(); - request_.SetRetrieveMainDicomTags(responseContent_ & ResponseContentFlags_MainDicomTags); request_.SetRetrieveMetadata((responseContent_ & ResponseContentFlags_Metadata) || (responseContent_ & ResponseContentFlags_MetadataLegacy)); request_.SetRetrieveLabels(responseContent_ & ResponseContentFlags_Labels); @@ -587,7 +611,6 @@ void ResourceFinder::SetDatabaseLimits(uint64_t limits) { databaseLimits_ = limits; - UpdateRequestLimits(); } @@ -601,7 +624,6 @@ { hasLimitsSince_ = true; limitsSince_ = since; - UpdateRequestLimits(); } } @@ -616,7 +638,6 @@ { hasLimitsCount_ = true; limitsCount_ = count; - UpdateRequestLimits(); } } @@ -646,7 +667,7 @@ } } - isSimpleLookup_ = registry.NormalizeLookup(request_.GetDicomTagConstraints(), lookup, request_.GetLevel()); + isSimpleLookup_ = registry.NormalizeLookup(canBeFullyPerformedInDb_, request_.GetDicomTagConstraints(), lookup, request_.GetLevel(), supportsChildExistQueries_); // "request_.GetDicomTagConstraints()" only contains constraints on main DICOM tags @@ -663,19 +684,20 @@ } else { - LOG(WARNING) << "Executing a database lookup at level " << EnumerationToString(request_.GetLevel()) - << " on main DICOM tag " << constraint.GetTag().Format() << " from an inferior level (" - << EnumerationToString(constraint.GetLevel()) << "), this will return no result"; + if (!supportsChildExistQueries_ || (constraint.GetLevel() != ResourceType_Series && constraint.GetTag() != DICOM_TAG_MODALITIES_IN_STUDY)) + { + LOG(WARNING) << "Executing a database lookup at level " << EnumerationToString(request_.GetLevel()) + << " on main DICOM tag " << constraint.GetTag().Format() << " from an inferior level (" + << EnumerationToString(constraint.GetLevel()) << "), this will return no result"; + } } - if (IsComputedTag(constraint.GetTag())) + if (IsComputedTag(constraint.GetTag()) && constraint.GetTag() != DICOM_TAG_MODALITIES_IN_STUDY) { // Sanity check throw OrthancException(ErrorCode_InternalError); } } - - UpdateRequestLimits(); } @@ -827,7 +849,8 @@ if (request_.GetLevel() != ResourceType_Instance) { - request_.SetRetrieveOneInstanceMetadataAndAttachments(true); + // only retrieve the instance attachments and metadata if we have allowed access to the storage + request_.SetRetrieveOneInstanceMetadataAndAttachments(IsStorageAccessAllowed()); } } } @@ -891,6 +914,19 @@ } + static void ConvertMetadata(std::map<MetadataType, std::string>& converted, + const FindResponse::Resource& resource) + { + const std::map<MetadataType, FindResponse::MetadataContent> metadata = resource.GetMetadata(ResourceType_Instance); + + for (std::map<MetadataType, FindResponse::MetadataContent>::const_iterator + it = metadata.begin(); it != metadata.end(); ++it) + { + converted[it->first] = it->second.GetValue(); + } + } + + static void ReadMissingTagsFromStorageArea(DicomMap& requestedTags, ServerContext& context, const FindRequest& request, @@ -920,7 +956,10 @@ { LOG(INFO) << "Will retrieve missing DICOM tags from instance: " << resource.GetIdentifier(); - context.ReadDicomAsJson(tmpDicomAsJson, resource.GetIdentifier(), resource.GetMetadata(ResourceType_Instance), + std::map<MetadataType, std::string> converted; + ConvertMetadata(converted, resource); + + context.ReadDicomAsJson(tmpDicomAsJson, resource.GetIdentifier(), converted, resource.GetAttachments(), missingTags /* ignoreTagLength */); } else if (request.GetLevel() != ResourceType_Instance && @@ -963,7 +1002,10 @@ if (request.GetLevel() == ResourceType_Instance) { - context.ReadDicomAsJson(tmpDicomAsJson, response.GetIdentifier(), response.GetMetadata(ResourceType_Instance), + std::map<MetadataType, std::string> converted; + ConvertMetadata(converted, resource); + + context.ReadDicomAsJson(tmpDicomAsJson, response.GetIdentifier(), converted, response.GetAttachments(), missingTags /* ignoreTagLength */); } else @@ -991,17 +1033,43 @@ } } + uint64_t ResourceFinder::Count(ServerContext& context) const + { + if (!canBeFullyPerformedInDb_) + { + throw OrthancException(ErrorCode_BadRequest, + "Unable to count resources when querying tags that are not stored as MainDicomTags in the Database or when using case sensitive queries."); + } + + uint64_t count = 0; + context.GetIndex().ExecuteCount(count, request_); + return count; + } + void ResourceFinder::Execute(IVisitor& visitor, - ServerContext& context) const + ServerContext& context) { + UpdateRequestLimits(context); + + if ((request_.HasLimits() && request_.GetLimitsSince() > 0) && + !canBeFullyPerformedInDb_) + { + throw OrthancException(ErrorCode_BadRequest, + "nable to use 'Since' when finding resources when querying against Dicom Tags that are not in the MainDicomTags or when using CaseSenstive queries."); + } + bool isWarning002Enabled = false; bool isWarning004Enabled = false; + bool isWarning006Enabled = false; + bool isWarning007Enabled = false; { OrthancConfiguration::ReaderLock lock; isWarning002Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_002_InconsistentDicomTagsInDb); isWarning004Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_004_NoMainDicomTagsSignature); + isWarning006Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_006_RequestingTagFromMetaHeader); + isWarning007Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_007_MissingRequestedTagsNotReadFromDisk); } FindResponse response; @@ -1059,18 +1127,43 @@ InjectRequestedTags(outRequestedTags, remainingRequestedTags, resource, ResourceType_Series); InjectRequestedTags(outRequestedTags, remainingRequestedTags, resource, ResourceType_Instance); + if (DicomMap::HasMetaInformationTags(remainingRequestedTags)) // we are not able to retrieve meta information in RequestedTags + { + std::set<DicomTag> metaTagsToRemove; + for (std::set<DicomTag>::const_iterator it = remainingRequestedTags.begin(); it != remainingRequestedTags.end(); ++it) + { + if (it->GetGroup() == 0x0002) + { + metaTagsToRemove.insert(*it); + } + } + + if (isWarning006Enabled) + { + std::string joinedMetaTags; + FromDcmtkBridge::FormatListOfTags(joinedMetaTags, metaTagsToRemove); + LOG(WARNING) << "W006: Unable to include tags from the Meta Header in \"RequestedTags\". Skipping them: " << joinedMetaTags; + } + + Toolbox::RemoveSets(remainingRequestedTags, metaTagsToRemove); + } + + if (!remainingRequestedTags.empty() && !DicomMap::HasOnlyComputedTags(remainingRequestedTags)) // if the only remaining tags are computed tags, it is worthless to read them from disk { - if (!allowStorageAccess_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Cannot add missing requested tags, as access to file storage is disallowed"); - } - else + // If a lookup tag is not available from DB, it is included in remainingRequestedTags and it will always be included in the answer too + // -> from 1.12.5, "StorageAccessOnFind": "Always" is actually equivalent to "StorageAccessOnFind": "Answers" + if (IsStorageAccessAllowed()) { ReadMissingTagsFromStorageArea(outRequestedTags, context, request_, resource, remainingRequestedTags); } + else if (isWarning007Enabled) + { + std::string joinedTags; + FromDcmtkBridge::FormatListOfTags(joinedTags, remainingRequestedTags); + LOG(WARNING) << "W007: Unable to include requested tags since \"StorageAccessOnFind\" does not allow accessing the storage to build answers: " << joinedTags; + } } std::string mainDicomTagsSignature; @@ -1142,11 +1235,24 @@ } } + bool ResourceFinder::IsStorageAccessAllowed() + { + switch (storageAccessMode_) + { + case FindStorageAccessMode_DiskOnAnswer: + case FindStorageAccessMode_DiskOnLookupAndAnswer: + return true; + case FindStorageAccessMode_DatabaseOnly: + return false; + default: + throw OrthancException(ErrorCode_InternalError); + } + } void ResourceFinder::Execute(Json::Value& target, ServerContext& context, DicomToJsonFormat format, - bool includeAllMetadata) const + bool includeAllMetadata) { class Visitor : public IVisitor { @@ -1202,6 +1308,8 @@ } }; + UpdateRequestLimits(context); + target = Json::arrayValue; Visitor visitor(*this, context.GetIndex(), target, format, HasRequestedTags(), includeAllMetadata); @@ -1212,7 +1320,7 @@ bool ResourceFinder::ExecuteOneResource(Json::Value& target, ServerContext& context, DicomToJsonFormat format, - bool includeAllMetadata) const + bool includeAllMetadata) { Json::Value answer; Execute(answer, context, format, includeAllMetadata);
--- a/OrthancServer/Sources/ResourceFinder.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ResourceFinder.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -60,13 +60,15 @@ uint64_t databaseLimits_; std::unique_ptr<DatabaseLookup> lookup_; bool isSimpleLookup_; + bool canBeFullyPerformedInDb_; PagingMode pagingMode_; bool hasLimitsSince_; bool hasLimitsCount_; uint64_t limitsSince_; uint64_t limitsCount_; ResponseContentFlags responseContent_; - bool allowStorageAccess_; + FindStorageAccessMode storageAccessMode_; + bool supportsChildExistQueries_; std::set<DicomTag> requestedTags_; std::set<DicomTag> requestedComputedTags_; @@ -94,29 +96,23 @@ void InjectComputedTags(DicomMap& requestedTags, const FindResponse::Resource& resource) const; - void UpdateRequestLimits(); + void UpdateRequestLimits(ServerContext& context); bool HasRequestedTags() const { return requestedTags_.size() > 0; } + bool IsStorageAccessAllowed(); + public: ResourceFinder(ResourceType level, - ResponseContentFlags responseContent); + ResponseContentFlags responseContent, + FindStorageAccessMode storageAccessMode, + bool supportsChildExistQueries); void SetDatabaseLimits(uint64_t limits); - bool IsAllowStorageAccess() const - { - return allowStorageAccess_; - } - - void SetAllowStorageAccess(bool allow) - { - allowStorageAccess_ = allow; - } - void SetOrthancId(ResourceType level, const std::string& id) { @@ -134,15 +130,17 @@ void AddRequestedTags(const std::set<DicomTag>& tags); void AddOrdering(const DicomTag& tag, + FindRequest::OrderingCast cast, FindRequest::OrderingDirection direction) { - request_.AddOrdering(tag, direction); + request_.AddOrdering(tag, cast, direction); } void AddOrdering(MetadataType metadataType, + FindRequest::OrderingCast cast, FindRequest::OrderingDirection direction) { - request_.AddOrdering(metadataType, direction); + request_.AddOrdering(metadataType, cast, direction); } void AddMetadataConstraint(DatabaseMetadataConstraint* constraint) @@ -187,16 +185,23 @@ DicomToJsonFormat format) const; void Execute(IVisitor& visitor, - ServerContext& context) const; + ServerContext& context); void Execute(Json::Value& target, ServerContext& context, DicomToJsonFormat format, - bool includeAllMetadata) const; + bool includeAllMetadata); bool ExecuteOneResource(Json::Value& target, ServerContext& context, DicomToJsonFormat format, - bool includeAllMetadata) const; + bool includeAllMetadata); + + uint64_t Count(ServerContext& context) const; + + bool CanBeFullyPerformedInDb() const + { + return canBeFullyPerformedInDb_; + } }; }
--- a/OrthancServer/Sources/Search/DatabaseDicomTagConstraint.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraint.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/DatabaseDicomTagConstraint.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraint.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/DatabaseDicomTagConstraints.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraints.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/DatabaseDicomTagConstraints.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraints.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/DatabaseLookup.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseLookup.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -282,6 +282,14 @@ bool DatabaseLookup::HasOnlyMainDicomTags() const { + std::set<DicomTag> notUsed; + + return HasOnlyMainDicomTags(notUsed); + } + + + bool DatabaseLookup::HasOnlyMainDicomTags(std::set<DicomTag>& /* out*/ nonMainDicomTags) const + { std::set<DicomTag> allMainTags; DicomMap::GetAllMainDicomTags(allMainTags); @@ -292,11 +300,11 @@ if (allMainTags.find(constraints_[i]->GetTag()) == allMainTags.end()) { // This is not a main DICOM tag - return false; + nonMainDicomTags.insert(constraints_[i]->GetTag()); } } - return true; + return nonMainDicomTags.size() == 0; }
--- a/OrthancServer/Sources/Search/DatabaseLookup.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseLookup.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -84,6 +84,8 @@ bool HasOnlyMainDicomTags() const; + bool HasOnlyMainDicomTags(std::set<DicomTag>& /* out*/ nonMainDicomTags) const; + std::string Format() const; bool HasTag(const DicomTag& tag) const;
--- a/OrthancServer/Sources/Search/DatabaseMetadataConstraint.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseMetadataConstraint.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/DatabaseMetadataConstraint.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DatabaseMetadataConstraint.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/DicomTagConstraint.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DicomTagConstraint.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/DicomTagConstraint.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/DicomTagConstraint.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/HierarchicalMatcher.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/HierarchicalMatcher.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/HierarchicalMatcher.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/HierarchicalMatcher.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/IDatabaseConstraint.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/IDatabaseConstraint.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/Search/ISqlLookupFormatter.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/ISqlLookupFormatter.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -766,7 +766,17 @@ // first filter by 0/1 and then by the column value itself orderByField += "order" + boost::lexical_cast<std::string>(counter) + ".value IS NULL, "; #endif - orderByField += "order" + boost::lexical_cast<std::string>(counter) + ".value"; + switch ((*it)->GetCast()) + { + case FindRequest::OrderingCast_Int: + orderByField += "CAST(order" + boost::lexical_cast<std::string>(counter) + ".value AS INTEGER)"; + break; + case FindRequest::OrderingCast_Float: + orderByField += "CAST(order" + boost::lexical_cast<std::string>(counter) + ".value AS REAL)"; + break; + default: + orderByField += "order" + boost::lexical_cast<std::string>(counter) + ".value"; + } if ((*it)->GetDirection() == FindRequest::OrderingDirection_Ascending) { @@ -846,13 +856,25 @@ { std::string join; FormatJoin(join, constraint, count); - joins += join; + + if (constraint.GetLevel() <= queryLevel) + { + joins += join; + } + else if (constraint.GetLevel() == queryLevel + 1 && !comparison.empty()) + { + // new in v 1.12.6, the constraints on child tags are actually looking for one child with this value + comparison = " EXISTS (SELECT 1 FROM Resources AS " + FormatLevel(static_cast<ResourceType>(queryLevel + 1)) + + join + + " WHERE " + comparison + " AND " + + FormatLevel(static_cast<ResourceType>(queryLevel + 1)) + ".parentId = " + FormatLevel(static_cast<ResourceType>(queryLevel)) + ".internalId) "; + } if (!comparison.empty()) { comparisons += " AND " + comparison; } - + count ++; } } @@ -884,13 +906,14 @@ FormatLevel(static_cast<ResourceType>(level + 1)) + ".parentId"); } - for (int level = queryLevel + 1; level <= lowerLevel; level++) - { - sql += (" INNER JOIN Resources " + - FormatLevel(static_cast<ResourceType>(level)) + " ON " + - FormatLevel(static_cast<ResourceType>(level - 1)) + ".internalId=" + - FormatLevel(static_cast<ResourceType>(level)) + ".parentId"); - } + // disabled in v 1.12.6 now that the child levels are considered as "is there at least one child that meets this constraint" + // for (int level = queryLevel + 1; level <= lowerLevel; level++) + // { + // sql += (" INNER JOIN Resources " + + // FormatLevel(static_cast<ResourceType>(level)) + " ON " + + // FormatLevel(static_cast<ResourceType>(level - 1)) + ".internalId=" + + // FormatLevel(static_cast<ResourceType>(level)) + ".parentId"); + // } std::list<std::string> where; where.push_back(strQueryLevel + ".resourceType = " +
--- a/OrthancServer/Sources/Search/ISqlLookupFormatter.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/Search/ISqlLookupFormatter.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -26,6 +26,7 @@ #include "../../../OrthancFramework/Sources/Enumerations.h" #include <boost/noncopyable.hpp> +#include <stdint.h> #include <vector> namespace Orthanc
--- a/OrthancServer/Sources/ServerContext.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerContext.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -50,6 +50,9 @@ #include <dcmtk/dcmdata/dcfilefo.h> #include <dcmtk/dcmnet/dimse.h> +#include <dcmtk/dcmdata/dcuid.h> /* for variable dcmAllStorageSOPClassUIDs */ + +#include <boost/regex.hpp> #if HAVE_MALLOC_TRIM == 1 # include <malloc.h> @@ -69,12 +72,6 @@ namespace Orthanc { - static void ComputeStudyTags(ExpandedResource& resource, - ServerContext& context, - const std::string& studyPublicId, - const std::set<DicomTag>& requestedTags); - - static bool IsUncompressedTransferSyntax(DicomTransferSyntax transferSyntax) { return (transferSyntax == DicomTransferSyntax_LittleEndianImplicit || @@ -362,7 +359,8 @@ IStorageArea& area, bool unitTesting, size_t maxCompletedJobs, - bool readOnly) : + bool readOnly, + unsigned int maxConcurrentDcmtkTranscoder) : index_(*this, database, (unitTesting ? 20 : 500), readOnly), area_(area), compressionEnabled_(false), @@ -384,7 +382,7 @@ isExecuteLuaEnabled_(false), isRestApiWriteToFileSystemEnabled_(false), overwriteInstances_(false), - dcmtkTranscoder_(new DcmtkTranscoder), + dcmtkTranscoder_(new DcmtkTranscoder(maxConcurrentDcmtkTranscoder)), isIngestTranscoding_(false), ingestTranscodingOfUncompressed_(true), ingestTranscodingOfCompressed_(true), @@ -495,6 +493,15 @@ lock.GetConfiguration().GetAcceptedTransferSyntaxes(acceptedTransferSyntaxes_); isUnknownSopClassAccepted_ = lock.GetConfiguration().GetBooleanParameter("UnknownSopClassAccepted", false); + + // New options in Orthanc 1.12.6 + std::list<std::string> acceptedSopClasses; + std::set<std::string> rejectedSopClasses; + lock.GetConfiguration().GetListOfStringsParameter(acceptedSopClasses, "AcceptedSopClasses"); + lock.GetConfiguration().GetSetOfStringsParameter(rejectedSopClasses, "RejectSopClasses"); + SetAcceptedSopClasses(acceptedSopClasses, rejectedSopClasses); + + defaultDicomRetrieveMethod_ = StringToRetrieveMethod(lock.GetConfiguration().GetStringParameter("DicomDefaultRetrieveMethod", "C-MOVE")); } jobsEngine_.SetThreadSleep(unitTesting ? 20 : 200); @@ -951,10 +958,20 @@ source.SetExternalBuffer(dicom->GetBufferData(), dicom->GetBufferSize()); IDicomTranscoder::DicomImage transcoded; + if (Transcode(transcoded, source, syntaxes, true /* allow new SOP instance UID */)) { std::unique_ptr<ParsedDicomFile> tmp(transcoded.ReleaseAsParsedDicomFile()); + if (isReconstruct) + { + // when reconstructing, we always want to keep the DICOM IDs untouched even if the transcoding has generated a new SOPInstanceUID. + const Orthanc::ParsedDicomFile& sourceDicom = dicom->GetParsedDicomFile(); + std::string sopInstanceUid; + sourceDicom.GetTagValue(sopInstanceUid, DICOM_TAG_SOP_INSTANCE_UID); + tmp->ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid); + } + std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromParsedDicomFile(*tmp)); toStore->SetOrigin(dicom->GetOrigin()); toStore->CopyMetadata(dicom->GetMetadata()); @@ -975,25 +992,15 @@ void ServerContext::AnswerAttachment(RestApiOutput& output, - const std::string& resourceId, - FileContentType content) + const FileInfo& attachment) { - FileInfo attachment; - int64_t revision; - if (!index_.LookupAttachment(attachment, revision, resourceId, content)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else - { - StorageAccessor accessor(area_, storageCache_, GetMetricsRegistry()); - accessor.AnswerFile(output, attachment, GetFileContentMime(content)); - } + StorageAccessor accessor(area_, storageCache_, GetMetricsRegistry()); + accessor.AnswerFile(output, attachment, GetFileContentMime(attachment.GetContentType())); } - void ServerContext::ChangeAttachmentCompression(const std::string& resourceId, - ResourceType resourceType, + void ServerContext::ChangeAttachmentCompression(ResourceType level, + const std::string& resourceId, FileContentType attachmentType, CompressionType compression) { @@ -1004,7 +1011,7 @@ FileInfo attachment; int64_t revision; - if (!index_.LookupAttachment(attachment, revision, resourceId, attachmentType)) + if (!index_.LookupAttachment(attachment, revision, level, resourceId, attachmentType)) { throw OrthancException(ErrorCode_UnknownResource); } @@ -1033,9 +1040,8 @@ // } // else { - ResourceType resourceType = ResourceType_Instance; //TODO_CUSTOM_DATA: get it from above in the stack - modified = accessor.WriteAttachment(newCustomData, resourceId, resourceType, content.empty() ? NULL : content.c_str(), - content.size(), attachmentType, compression, storeMD5_, newUuid); + modified = accessor.WriteAttachment(newCustomData, resourceId, level, content.empty() ? NULL : content.c_str(), + content.size(), attachmentType, compression, storeMD5_, newUuid); } @@ -1123,23 +1129,23 @@ FileInfo attachment; int64_t revision; // Ignored - if (index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_Dicom)) + if (index_.LookupAttachment(attachment, revision, ResourceType_Instance, instancePublicId, FileContentType_Dicom)) { attachments[FileContentType_Dicom] = attachment; } - if (index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_DicomUntilPixelData)) + if (index_.LookupAttachment(attachment, revision, ResourceType_Instance, instancePublicId, FileContentType_DicomUntilPixelData)) { attachments[FileContentType_DicomUntilPixelData] = attachment; } - if (index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_DicomAsJson)) + if (index_.LookupAttachment(attachment, revision, ResourceType_Instance, instancePublicId, FileContentType_DicomAsJson)) { attachments[FileContentType_DicomAsJson] = attachment; } std::string s; - if (index_.LookupMetadata(s, revision, instancePublicId, ResourceType_Instance, + if (index_.LookupMetadata(s, instancePublicId, ResourceType_Instance, MetadataType_Instance_PixelDataOffset)) { metadata[MetadataType_Instance_PixelDataOffset] = s; @@ -1325,8 +1331,20 @@ std::string& attachmentId, const std::string& instancePublicId) { + FileInfo attachment; int64_t revision; - ReadAttachment(dicom, revision, attachmentId, instancePublicId, FileContentType_Dicom, true /* uncompress */); + + if (!index_.LookupAttachment(attachment, revision, ResourceType_Instance, instancePublicId, FileContentType_Dicom)) + { + throw OrthancException(ErrorCode_InternalError, + "Unable to read attachment " + EnumerationToString(FileContentType_Dicom) + + " of instance " + instancePublicId); + } + + assert(attachment.GetContentType() == FileContentType_Dicom); + attachmentId = attachment.GetUuid(); + + ReadAttachment(dicom, attachment, true /* uncompress */); } @@ -1351,7 +1369,7 @@ { FileInfo attachment; int64_t revision; // Ignored - if (index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_DicomUntilPixelData)) + if (index_.LookupAttachment(attachment, revision, ResourceType_Instance, instancePublicId, FileContentType_DicomUntilPixelData)) { StorageAccessor accessor(area_, storageCache_, GetMetricsRegistry()); @@ -1366,7 +1384,7 @@ return false; } - if (!index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_Dicom)) + if (!index_.LookupAttachment(attachment, revision, ResourceType_Instance, instancePublicId, FileContentType_Dicom)) { throw OrthancException(ErrorCode_InternalError, "Unable to read the DICOM file of instance " + instancePublicId); @@ -1375,7 +1393,7 @@ std::string s; if (attachment.GetCompressionType() == CompressionType_None && - index_.LookupMetadata(s, revision, instancePublicId, ResourceType_Instance, + index_.LookupMetadata(s, instancePublicId, ResourceType_Instance, MetadataType_Instance_PixelDataOffset) && !s.empty()) { @@ -1401,47 +1419,40 @@ void ServerContext::ReadAttachment(std::string& result, - int64_t& revision, - std::string& attachmentId, - const std::string& instancePublicId, - FileContentType content, + const FileInfo& attachment, bool uncompressIfNeeded, bool skipCache) { - FileInfo attachment; - if (!index_.LookupAttachment(attachment, revision, instancePublicId, content)) + std::unique_ptr<StorageAccessor> accessor; + + if (skipCache) { - throw OrthancException(ErrorCode_InternalError, - "Unable to read attachment " + EnumerationToString(content) + - " of instance " + instancePublicId); + accessor.reset(new StorageAccessor(area_, GetMetricsRegistry())); + } + else + { + accessor.reset(new StorageAccessor(area_, storageCache_, GetMetricsRegistry())); } - assert(attachment.GetContentType() == content); - attachmentId = attachment.GetUuid(); - + if (uncompressIfNeeded) + { + accessor->Read(result, attachment); + } + else { - std::unique_ptr<StorageAccessor> accessor; - - if (skipCache) - { - accessor.reset(new StorageAccessor(area_, GetMetricsRegistry())); - } - else - { - accessor.reset(new StorageAccessor(area_, storageCache_, GetMetricsRegistry())); - } + // Do not uncompress the content of the storage area, return the + // raw data + accessor->ReadRaw(result, attachment); + } + } - if (uncompressIfNeeded) - { - accessor->Read(result, attachment); - } - else - { - // Do not uncompress the content of the storage area, return the - // raw data - accessor->ReadRaw(result, attachment); - } - } + void ServerContext::ReadAttachmentRange(std::string &result, + const FileInfo &attachment, + const StorageAccessor::Range &range, + bool uncompressIfNeeded) + { + StorageAccessor accessor(area_, storageCache_, GetMetricsRegistry()); + accessor.ReadRange(result, attachment, range, uncompressIfNeeded); } @@ -1661,188 +1672,6 @@ } - void ServerContext::Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, - LabelsConstraint labelsConstraint, - size_t since, - size_t limit) - { - const uint64_t databaseLimit = GetDatabaseLimits(queryLevel); - - std::vector<std::string> resources, instances; - const DicomTagConstraint* dicomModalitiesConstraint = NULL; - - bool hasModalitiesInStudyLookup = (queryLevel == ResourceType_Study && - lookup.GetConstraint(dicomModalitiesConstraint, DICOM_TAG_MODALITIES_IN_STUDY) && - ((dicomModalitiesConstraint->GetConstraintType() == ConstraintType_Equal && !dicomModalitiesConstraint->GetValue().empty()) || - (dicomModalitiesConstraint->GetConstraintType() == ConstraintType_List && !dicomModalitiesConstraint->GetValues().empty()))); - - std::unique_ptr<DatabaseLookup> fastLookup(lookup.Clone()); - - if (hasModalitiesInStudyLookup) - { - fastLookup->RemoveConstraint(DICOM_TAG_MODALITIES_IN_STUDY); - } - - const size_t lookupLimit = (databaseLimit == 0 ? 0 : databaseLimit + 1); - GetIndex().ApplyLookupResources(resources, &instances, *fastLookup, queryLevel, labels, labelsConstraint, lookupLimit); - - bool complete = (databaseLimit == 0 || - resources.size() <= databaseLimit); - - LOG(INFO) << "Number of candidate resources after fast DB filtering on main DICOM tags: " << resources.size(); - - /** - * "resources" contains the Orthanc ID of the resource at level - * "queryLevel", "instances" contains one the Orthanc ID of one - * sample instance from this resource. - **/ - assert(resources.size() == instances.size()); - - size_t countResults = 0; - size_t skipped = 0; - - const bool isDicomAsJsonNeeded = visitor.IsDicomAsJsonNeeded(); - - for (size_t i = 0; i < instances.size(); i++) - { - // Optimization in Orthanc 1.5.1 - Don't read the full JSON from - // the disk if only "main DICOM tags" are to be returned - - boost::shared_ptr<Json::Value> dicomAsJson; - - bool hasOnlyMainDicomTags; - DicomMap dicom; - DicomMap allMainDicomTagsFromDB; - - if (!IsStorageAccessAllowedForAnswers(findStorageAccessMode_) - || fastLookup->HasOnlyMainDicomTags()) - { - // Case (1): The main DICOM tags, as stored in the database, - // are sufficient to look for match - - if (!GetIndex().GetAllMainDicomTags(allMainDicomTagsFromDB, instances[i])) - { - // The instance has been removed during the execution of the - // lookup, ignore it - continue; - } - - // New in Orthanc 1.6.0: Only keep the main DICOM tags at the - // level of interest for the query - switch (queryLevel) - { - // WARNING: Don't reorder cases below, and don't add "break" - case ResourceType_Instance: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Instance); - - case ResourceType_Series: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Series); - - case ResourceType_Study: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Study); - - case ResourceType_Patient: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Patient); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - hasOnlyMainDicomTags = true; - } - else - { - // Case (2): Need to read the "DICOM-as-JSON" attachment from - // the storage area - dicomAsJson.reset(new Json::Value); - ReadDicomAsJson(*dicomAsJson, instances[i]); - - dicom.FromDicomAsJson(*dicomAsJson); - - // This map contains the entire JSON, i.e. more than the main DICOM tags - hasOnlyMainDicomTags = false; - } - - if (fastLookup->IsMatch(dicom)) - { - bool isMatch = true; - - if (hasModalitiesInStudyLookup) - { - std::set<DicomTag> requestedTags; - requestedTags.insert(DICOM_TAG_MODALITIES_IN_STUDY); - ExpandedResource resource; - ComputeStudyTags(resource, *this, resources[i], requestedTags); - - std::vector<std::string> modalities; - Toolbox::TokenizeString(modalities, resource.GetMainDicomTags().GetValue(DICOM_TAG_MODALITIES_IN_STUDY).GetContent(), '\\'); - bool hasAtLeastOneModalityMatching = false; - for (size_t m = 0; m < modalities.size(); m++) - { - hasAtLeastOneModalityMatching |= dicomModalitiesConstraint->IsMatch(modalities[m]); - } - - isMatch = isMatch && hasAtLeastOneModalityMatching; - // copy the value of ModalitiesInStudy such that it can be reused to build the answer - allMainDicomTagsFromDB.SetValue(DICOM_TAG_MODALITIES_IN_STUDY, resource.GetMainDicomTags().GetValue(DICOM_TAG_MODALITIES_IN_STUDY)); - } - - if (isMatch) - { - if (skipped < since) - { - skipped++; - } - else if (limit != 0 && - countResults >= limit) - { - // Too many results, don't mark as complete - complete = false; - break; - } - else - { - if (IsStorageAccessAllowedForAnswers(findStorageAccessMode_) && - dicomAsJson.get() == NULL && - isDicomAsJsonNeeded) - { - dicomAsJson.reset(new Json::Value); - ReadDicomAsJson(*dicomAsJson, instances[i]); - } - - if (hasOnlyMainDicomTags) - { - // This is Case (1): The variable "dicom" only contains the main DICOM tags - visitor.Visit(resources[i], instances[i], allMainDicomTagsFromDB, dicomAsJson.get()); - } - else - { - // Remove the non-main DICOM tags from "dicom" if Case (2) - // was used, for consistency with Case (1) - - DicomMap mainDicomTags; - mainDicomTags.ExtractMainDicomTags(dicom); - visitor.Visit(resources[i], instances[i], mainDicomTags, dicomAsJson.get()); - } - - countResults ++; - } - } - } - } - - if (complete) - { - visitor.MarkAsComplete(); - } - - LOG(INFO) << "Number of matching resources: " << countResults; - } - bool ServerContext::LookupOrReconstructMetadata(std::string& target, const std::string& publicId, ResourceType level, @@ -1855,8 +1684,7 @@ if (metadata == MetadataType_Instance_SopClassUid || metadata == MetadataType_Instance_TransferSyntax) { - int64_t revision; // Ignored - if (index_.LookupMetadata(target, revision, publicId, level, metadata)) + if (index_.LookupMetadata(target, publicId, level, metadata)) { return true; } @@ -1911,8 +1739,7 @@ else { // No backward - int64_t revision; // Ignored - return index_.LookupMetadata(target, revision, publicId, level, metadata); + return index_.LookupMetadata(target, publicId, level, metadata); } } @@ -2224,8 +2051,118 @@ } } + void ServerContext::SetAcceptedSopClasses(const std::list<std::string>& acceptedSopClasses, + const std::set<std::string>& rejectedSopClasses) + { + boost::mutex::scoped_lock lock(dynamicOptionsMutex_); + acceptedSopClasses_.clear(); - void ServerContext::GetAcceptedTransferSyntaxes(std::set<DicomTransferSyntax>& syntaxes) + size_t count = 0; + std::set<std::string> allDcmtkSopClassUids; + std::set<std::string> shortDcmtkSopClassUids; + + // we actually take a list of default 120 most common storage SOP classes defined in DCMTK + while (dcmLongSCUStorageSOPClassUIDs[count] != NULL) + { + shortDcmtkSopClassUids.insert(dcmLongSCUStorageSOPClassUIDs[count++]); + } + + count = 0; + while (dcmAllStorageSOPClassUIDs[count] != NULL) + { + allDcmtkSopClassUids.insert(dcmAllStorageSOPClassUIDs[count++]); + } + + if (acceptedSopClasses.size() == 0) + { + // by default, include the short list first and then all the others + for (std::set<std::string>::const_iterator it = shortDcmtkSopClassUids.begin(); it != shortDcmtkSopClassUids.end(); ++it) + { + acceptedSopClasses_.push_back(*it); + } + + for (std::set<std::string>::const_iterator it = allDcmtkSopClassUids.begin(); it != allDcmtkSopClassUids.end(); ++it) + { + if (shortDcmtkSopClassUids.find(*it) == shortDcmtkSopClassUids.end()) // don't add the classes that we have already added + { + acceptedSopClasses_.push_back(*it); + } + } + } + else + { + std::set<std::string> addedSopClasses; + + for (std::list<std::string>::const_iterator it = acceptedSopClasses.begin(); it != acceptedSopClasses.end(); ++it) + { + if (it->find('*') != std::string::npos || it->find('?') != std::string::npos) + { + // if it contains wildcard, add all the matching SOP classes known by DCMTK + boost::regex pattern(Toolbox::WildcardToRegularExpression(*it)); + + for (std::set<std::string>::const_iterator itall = allDcmtkSopClassUids.begin(); itall != allDcmtkSopClassUids.end(); ++itall) + { + if (regex_match(*itall, pattern) && addedSopClasses.find(*itall) == addedSopClasses.end()) + { + acceptedSopClasses_.push_back(*itall); + addedSopClasses.insert(*itall); + } + } + } + else + { + // if it is a SOP Class UID, add it without checking if it is known by DCMTK + acceptedSopClasses_.push_back(*it); + addedSopClasses.insert(*it); + } + } + } + + // now remove all rejected syntaxes + if (rejectedSopClasses.size() > 0) + { + for (std::set<std::string>::const_iterator it = rejectedSopClasses.begin(); it != rejectedSopClasses.end(); ++it) + { + if (it->find('*') != std::string::npos || it->find('?') != std::string::npos) + { + // if it contains wildcard, get all the matching SOP classes known by DCMTK + boost::regex pattern(Toolbox::WildcardToRegularExpression(*it)); + + for (std::set<std::string>::const_iterator itall = allDcmtkSopClassUids.begin(); itall != allDcmtkSopClassUids.end(); ++itall) + { + if (regex_match(*itall, pattern)) + { + acceptedSopClasses_.remove(*itall); + } + } + } + else + { + // if it is a SOP Class UID, remove it without checking if it is known by DCMTK + acceptedSopClasses_.remove(*it); + } + } + } + } + + void ServerContext::GetAcceptedSopClasses(std::set<std::string>& sopClasses, size_t maxCount) const + { + sopClasses.clear(); + + boost::mutex::scoped_lock lock(dynamicOptionsMutex_); + + size_t count = 0; + std::list<std::string>::const_iterator it = acceptedSopClasses_.begin(); + + while (it != acceptedSopClasses_.end() && (maxCount == 0 || count < maxCount)) + { + sopClasses.insert(*it); + count++; + ++it; + } + } + + void ServerContext::GetAcceptedTransferSyntaxes(std::set<DicomTransferSyntax>& syntaxes) const { boost::mutex::scoped_lock lock(dynamicOptionsMutex_); syntaxes = acceptedTransferSyntaxes_; @@ -2239,7 +2176,25 @@ } - bool ServerContext::IsUnknownSopClassAccepted() + void ServerContext::GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& syntaxes) const + { + boost::mutex::scoped_lock lock(dynamicOptionsMutex_); + + // // TODO: investigate: actually, neither Orthanc 1.12.4 nor DCM4CHEE will accept to send a LittleEndianExplicit file + // // while e.g., Jpeg-LS has been presented (and accepted) as the preferred TS for the C-Store SCP. + // // if we have defined IngestTranscoding, let's propose this TS first to avoid any unnecessary transcoding + // if (isIngestTranscoding_) + // { + // syntaxes.push_back(ingestTransferSyntax_); + // } + + // then, propose the default ones + syntaxes.push_back(DicomTransferSyntax_LittleEndianExplicit); + syntaxes.push_back(DicomTransferSyntax_LittleEndianImplicit); + } + + + bool ServerContext::IsUnknownSopClassAccepted() const { boost::mutex::scoped_lock lock(dynamicOptionsMutex_); return isUnknownSopClassAccepted_; @@ -2252,600 +2207,6 @@ isUnknownSopClassAccepted_ = accepted; } - - static void SerializeExpandedResource(Json::Value& target, - const ExpandedResource& resource, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - ExpandResourceFlags expandFlags) - { - target = Json::objectValue; - - target["Type"] = GetResourceTypeText(resource.GetLevel(), false, true); - target["ID"] = resource.GetPublicId(); - - if (!resource.parentId_.empty()) - { - switch (resource.GetLevel()) - { - case ResourceType_Patient: - break; - - case ResourceType_Study: - target["ParentPatient"] = resource.parentId_; - break; - - case ResourceType_Series: - target["ParentStudy"] = resource.parentId_; - break; - - case ResourceType_Instance: - target["ParentSeries"] = resource.parentId_; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - if ((expandFlags & ExpandResourceFlags_IncludeChildren) != 0) - { - switch (resource.GetLevel()) - { - case ResourceType_Patient: - case ResourceType_Study: - case ResourceType_Series: - { - Json::Value c = Json::arrayValue; - - for (std::list<std::string>::const_iterator - it = resource.childrenIds_.begin(); it != resource.childrenIds_.end(); ++it) - { - c.append(*it); - } - - if (resource.GetLevel() == ResourceType_Patient) - { - target["Studies"] = c; - } - else if (resource.GetLevel() == ResourceType_Study) - { - target["Series"] = c; - } - else - { - target["Instances"] = c; - } - break; - } - - case ResourceType_Instance: - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - if ((expandFlags & ExpandResourceFlags_IncludeMetadata) != 0) - { - switch (resource.GetLevel()) - { - case ResourceType_Patient: - case ResourceType_Study: - break; - - case ResourceType_Series: - if (resource.expectedNumberOfInstances_ < 0) - { - target["ExpectedNumberOfInstances"] = Json::nullValue; - } - else - { - target["ExpectedNumberOfInstances"] = resource.expectedNumberOfInstances_; - } - target["Status"] = resource.status_; - break; - - case ResourceType_Instance: - { - target["FileSize"] = static_cast<unsigned int>(resource.fileSize_); - target["FileUuid"] = resource.fileUuid_; - - if (resource.indexInSeries_ < 0) - { - target["IndexInSeries"] = Json::nullValue; - } - else - { - target["IndexInSeries"] = resource.indexInSeries_; - } - - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - if (!resource.anonymizedFrom_.empty()) - { - target["AnonymizedFrom"] = resource.anonymizedFrom_; - } - - if (!resource.modifiedFrom_.empty()) - { - target["ModifiedFrom"] = resource.modifiedFrom_; - } - } - - if (resource.GetLevel() == ResourceType_Patient || - resource.GetLevel() == ResourceType_Study || - resource.GetLevel() == ResourceType_Series) - { - if ((expandFlags & ExpandResourceFlags_IncludeIsStable) != 0) - { - target["IsStable"] = resource.isStable_; - } - - if (!resource.lastUpdate_.empty()) - { - target["LastUpdate"] = resource.lastUpdate_; - } - } - - if ((expandFlags & ExpandResourceFlags_IncludeMainDicomTags) != 0) - { - // serialize tags - - static const char* const MAIN_DICOM_TAGS = "MainDicomTags"; - static const char* const PATIENT_MAIN_DICOM_TAGS = "PatientMainDicomTags"; - - DicomMap mainDicomTags; - resource.GetMainDicomTags().ExtractResourceInformation(mainDicomTags, resource.GetLevel()); - - target[MAIN_DICOM_TAGS] = Json::objectValue; - FromDcmtkBridge::ToJson(target[MAIN_DICOM_TAGS], mainDicomTags, format); - - if (resource.GetLevel() == ResourceType_Study) - { - DicomMap patientMainDicomTags; - resource.GetMainDicomTags().ExtractPatientInformation(patientMainDicomTags); - - target[PATIENT_MAIN_DICOM_TAGS] = Json::objectValue; - FromDcmtkBridge::ToJson(target[PATIENT_MAIN_DICOM_TAGS], patientMainDicomTags, format); - } - - if (requestedTags.size() > 0) - { - static const char* const REQUESTED_TAGS = "RequestedTags"; - - DicomMap tags; - resource.GetMainDicomTags().ExtractTags(tags, requestedTags); - - target[REQUESTED_TAGS] = Json::objectValue; - FromDcmtkBridge::ToJson(target[REQUESTED_TAGS], tags, format); - - } - } - - if ((expandFlags & ExpandResourceFlags_IncludeLabels) != 0) - { - Json::Value labels = Json::arrayValue; - - for (std::set<std::string>::const_iterator it = resource.labels_.begin(); it != resource.labels_.end(); ++it) - { - labels.append(*it); - } - - target["Labels"] = labels; - } - - // new in Orthanc 1.12.4 - if ((expandFlags & ExpandResourceFlags_IncludeAllMetadata) != 0) - { - Json::Value metadata = Json::objectValue; - - for (std::map<MetadataType, std::string>::const_iterator it = resource.metadata_.begin(); it != resource.metadata_.end(); ++it) - { - metadata[EnumerationToString(it->first)] = it->second; - } - - target["Metadata"] = metadata; - } - } - - - static void ComputeInstanceTags(ExpandedResource& resource, - ServerContext& context, - const std::string& instancePublicId, - const std::set<DicomTag>& requestedTags) - { - if (requestedTags.count(DICOM_TAG_INSTANCE_AVAILABILITY) > 0) - { - resource.GetMainDicomTags().SetValue(DICOM_TAG_INSTANCE_AVAILABILITY, "ONLINE", false); - resource.missingRequestedTags_.erase(DICOM_TAG_INSTANCE_AVAILABILITY); - } - } - - - static void ComputeSeriesTags(ExpandedResource& resource, - ServerContext& context, - const std::string& seriesPublicId, - const std::set<DicomTag>& requestedTags) - { - if (requestedTags.count(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES) > 0) - { - ServerIndex& index = context.GetIndex(); - std::list<std::string> instances; - - index.GetChildren(instances, seriesPublicId); - - resource.GetMainDicomTags().SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES, - boost::lexical_cast<std::string>(instances.size()), false); - resource.missingRequestedTags_.erase(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES); - } - } - - static void ComputeStudyTags(ExpandedResource& resource, - ServerContext& context, - const std::string& studyPublicId, - const std::set<DicomTag>& requestedTags) - { - ServerIndex& index = context.GetIndex(); - std::list<std::string> series; - std::list<std::string> instances; - - bool hasNbRelatedSeries = requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES) > 0; - bool hasNbRelatedInstances = requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) > 0; - bool hasModalitiesInStudy = requestedTags.count(DICOM_TAG_MODALITIES_IN_STUDY) > 0; - bool hasSopClassesInStudy = requestedTags.count(DICOM_TAG_SOP_CLASSES_IN_STUDY) > 0; - - index.GetChildren(series, studyPublicId); - - if (hasModalitiesInStudy) - { - std::set<std::string> values; - - for (std::list<std::string>::const_iterator - it = series.begin(); it != series.end(); ++it) - { - DicomMap tags; - index.GetMainDicomTags(tags, *it, ResourceType_Series, ResourceType_Series); - - const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - values.insert(value->GetContent()); - } - } - - std::string modalities; - Toolbox::JoinStrings(modalities, values, "\\"); - - resource.GetMainDicomTags().SetValue(DICOM_TAG_MODALITIES_IN_STUDY, modalities, false); - resource.missingRequestedTags_.erase(DICOM_TAG_MODALITIES_IN_STUDY); - } - - if (hasNbRelatedSeries) - { - resource.GetMainDicomTags().SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES, - boost::lexical_cast<std::string>(series.size()), false); - resource.missingRequestedTags_.erase(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES); - } - - if (hasNbRelatedInstances || hasSopClassesInStudy) - { - for (std::list<std::string>::const_iterator - it = series.begin(); it != series.end(); ++it) - { - std::list<std::string> seriesInstancesIds; - index.GetChildren(seriesInstancesIds, *it); - - instances.splice(instances.end(), seriesInstancesIds); - } - - if (hasNbRelatedInstances) - { - resource.GetMainDicomTags().SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES, - boost::lexical_cast<std::string>(instances.size()), false); - resource.missingRequestedTags_.erase(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES); - } - - if (hasSopClassesInStudy) - { - std::set<std::string> values; - - for (std::list<std::string>::const_iterator - it = instances.begin(); it != instances.end(); ++it) - { - std::string value; - - if (context.LookupOrReconstructMetadata(value, *it, ResourceType_Instance, MetadataType_Instance_SopClassUid)) - { - values.insert(value); - } - } - - if (values.size() > 0) - { - std::string sopClassUids; - Toolbox::JoinStrings(sopClassUids, values, "\\"); - resource.GetMainDicomTags().SetValue(DICOM_TAG_SOP_CLASSES_IN_STUDY, sopClassUids, false); - } - - resource.missingRequestedTags_.erase(DICOM_TAG_SOP_CLASSES_IN_STUDY); - } - } - } - - static void ComputePatientTags(ExpandedResource& resource, - ServerContext& context, - const std::string& patientPublicId, - const std::set<DicomTag>& requestedTags) - { - ServerIndex& index = context.GetIndex(); - - std::list<std::string> studies; - std::list<std::string> series; - std::list<std::string> instances; - - bool hasNbRelatedStudies = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES) > 0; - bool hasNbRelatedSeries = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) > 0; - bool hasNbRelatedInstances = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES) > 0; - - index.GetChildren(studies, patientPublicId); - - if (hasNbRelatedStudies) - { - resource.GetMainDicomTags().SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES, - boost::lexical_cast<std::string>(studies.size()), false); - resource.missingRequestedTags_.erase(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES); - } - - if (hasNbRelatedSeries || hasNbRelatedInstances) - { - for (std::list<std::string>::const_iterator - it = studies.begin(); it != studies.end(); ++it) - { - std::list<std::string> thisSeriesIds; - index.GetChildren(thisSeriesIds, *it); - series.splice(series.end(), thisSeriesIds); - } - - if (hasNbRelatedSeries) - { - resource.GetMainDicomTags().SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES, - boost::lexical_cast<std::string>(series.size()), false); - resource.missingRequestedTags_.erase(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES); - } - } - - if (hasNbRelatedInstances) - { - for (std::list<std::string>::const_iterator - it = series.begin(); it != series.end(); ++it) - { - std::list<std::string> thisInstancesIds; - index.GetChildren(thisInstancesIds, *it); - instances.splice(instances.end(), thisInstancesIds); - } - - resource.GetMainDicomTags().SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES, - boost::lexical_cast<std::string>(instances.size()), false); - resource.missingRequestedTags_.erase(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES); - } - } - - - static void ComputeTags(ExpandedResource& resource, - ServerContext& context, - const std::string& resourceId, - ResourceType level, - const std::set<DicomTag>& requestedTags) - { - if (level == ResourceType_Patient - && DicomMap::HasComputedTags(resource.missingRequestedTags_, ResourceType_Patient)) - { - ComputePatientTags(resource, context, resourceId, requestedTags); - } - - if (level == ResourceType_Study - && DicomMap::HasComputedTags(resource.missingRequestedTags_, ResourceType_Study)) - { - ComputeStudyTags(resource, context, resourceId, requestedTags); - } - - if (level == ResourceType_Series - && DicomMap::HasComputedTags(resource.missingRequestedTags_, ResourceType_Series)) - { - ComputeSeriesTags(resource, context, resourceId, requestedTags); - } - - if (level == ResourceType_Instance - && DicomMap::HasComputedTags(resource.missingRequestedTags_, ResourceType_Instance)) - { - ComputeInstanceTags(resource, context, resourceId, requestedTags); - } - } - - bool ServerContext::ExpandResource(Json::Value& target, - const std::string& publicId, - ResourceType level, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess) - { - std::string unusedInstanceId; - Json::Value* unusedDicomAsJson = NULL; - DicomMap unusedMainDicomTags; - - return ExpandResource(target, publicId, unusedMainDicomTags, unusedInstanceId, unusedDicomAsJson, level, format, requestedTags, allowStorageAccess); - } - - bool ServerContext::ExpandResource(Json::Value& target, - const std::string& publicId, - const DicomMap& mainDicomTags, // optional: the main dicom tags for the resource (if already available) - const std::string& instanceId, // optional: the id of an instance for the resource (if already available) - const Json::Value* dicomAsJson, // optional: the dicom-as-json for the resource (if already available) - ResourceType level, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess) - { - ExpandedResource resource; - - if (ExpandResource(resource, publicId, mainDicomTags, instanceId, dicomAsJson, level, requestedTags, ExpandResourceFlags_DefaultExtract, allowStorageAccess)) - { - SerializeExpandedResource(target, resource, format, requestedTags, ExpandResourceFlags_DefaultOutput); - return true; - } - - return false; - } - - bool ServerContext::ExpandResource(ExpandedResource& resource, - const std::string& publicId, - const DicomMap& mainDicomTags, // optional: the main dicom tags for the resource (if already available) - const std::string& instanceId, // optional: the id of an instance for the resource (if already available) - const Json::Value* dicomAsJson, // optional: the dicom-as-json for the resource (if already available) - ResourceType level, - const std::set<DicomTag>& requestedTags, - ExpandResourceFlags expandFlags, - bool allowStorageAccess) - { - // first try to get the tags from what is already available - - if ((expandFlags & ExpandResourceFlags_IncludeMainDicomTags) && - mainDicomTags.GetSize() > 0 && - dicomAsJson != NULL) - { - - resource.GetMainDicomTags().Merge(mainDicomTags); - - if (dicomAsJson->isObject()) - { - resource.GetMainDicomTags().FromDicomAsJson(*dicomAsJson); - } - - std::set<DicomTag> retrievedTags; - std::set<DicomTag> missingTags; - resource.GetMainDicomTags().GetTags(retrievedTags); - - Toolbox::GetMissingsFromSet(missingTags, requestedTags, retrievedTags); - - // if all possible tags have been read, no need to get them from DB anymore - if (missingTags.size() > 0 && DicomMap::HasOnlyComputedTags(missingTags)) - { - resource.missingRequestedTags_ = missingTags; - ComputeTags(resource, *this, publicId, level, requestedTags); - return true; - } - else if (missingTags.size() == 0) - { - expandFlags = static_cast<ExpandResourceFlags>(expandFlags & ~ExpandResourceFlags_IncludeMainDicomTags); - } - - if (missingTags.size() == 0 && expandFlags == ExpandResourceFlags_None) // we have already retrieved anything we need - { - return true; - } - } - - if (expandFlags != ExpandResourceFlags_None && - GetIndex().ExpandResource(resource, publicId, level, requestedTags, - static_cast<ExpandResourceFlags>(expandFlags | ExpandResourceFlags_IncludeMetadata))) // we always need the metadata to get the mainDicomTagsSignature - { - // check the main dicom tags list has not changed since the resource was stored - if (resource.mainDicomTagsSignature_ != DicomMap::GetMainDicomTagsSignature(resource.GetLevel())) - { - OrthancConfiguration::ReaderLock lock; - if (lock.GetConfiguration().IsWarningEnabled(Warnings_002_InconsistentDicomTagsInDb)) - { - LOG(WARNING) << "W002: " << Orthanc::GetResourceTypeText(resource.GetLevel(), false , false) - << " has been stored with another version of Main Dicom Tags list, you should POST to /" - << Orthanc::GetResourceTypeText(resource.GetLevel(), true, false) - << "/" << resource.GetPublicId() - << "/reconstruct to update the list of tags saved in DB. Some MainDicomTags might be missing from this answer."; - } - } - - // possibly merge missing requested tags from dicom-as-json - if (allowStorageAccess && - !resource.missingRequestedTags_.empty() && - !DicomMap::HasOnlyComputedTags(resource.missingRequestedTags_)) - { - OrthancConfiguration::ReaderLock lock; - if (lock.GetConfiguration().IsWarningEnabled(Warnings_001_TagsBeingReadFromStorage)) - { - std::set<DicomTag> missingTags; - Toolbox::AppendSets(missingTags, resource.missingRequestedTags_); - for (std::set<DicomTag>::const_iterator it = resource.missingRequestedTags_.begin(); it != resource.missingRequestedTags_.end(); ++it) - { - if (DicomMap::IsComputedTag(*it)) - { - missingTags.erase(*it); - } - } - - std::string missings; - FromDcmtkBridge::FormatListOfTags(missings, missingTags); - - LOG(WARNING) << "W001: Accessing Dicom tags from storage when accessing " - << Orthanc::GetResourceTypeText(resource.GetLevel(), false, false) - << " : " << missings; - } - - - std::string instanceId_ = instanceId; - DicomMap tagsFromJson; - - if (dicomAsJson == NULL) - { - if (instanceId_.empty()) - { - if (level == ResourceType_Instance) - { - instanceId_ = publicId; - } - else - { - std::list<std::string> instancesIds; - GetIndex().GetChildInstances(instancesIds, publicId); - if (instancesIds.size() < 1) - { - throw OrthancException(ErrorCode_InternalError, "ExpandResource: no instances found"); - } - instanceId_ = instancesIds.front(); - } - } - - Json::Value tmpDicomAsJson; - ReadDicomAsJson(tmpDicomAsJson, instanceId_, resource.missingRequestedTags_ /* ignoreTagLength */); // read all tags from DICOM and avoid cropping requested tags - tagsFromJson.FromDicomAsJson(tmpDicomAsJson, false /* append */, true /* parseSequences*/); - } - else - { - tagsFromJson.FromDicomAsJson(*dicomAsJson, false /* append */, true /* parseSequences*/); - } - - resource.GetMainDicomTags().Merge(tagsFromJson); - } - - // compute the requested tags - ComputeTags(resource, *this, publicId, level, requestedTags); - } - else - { - return false; - } - - return true; - } - int64_t ServerContext::GetServerUpTime() const { boost::posix_time::ptime nowUtc = boost::posix_time::second_clock::universal_time();
--- a/OrthancServer/Sources/ServerContext.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerContext.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -38,6 +38,8 @@ #include <boost/date_time/posix_time/posix_time.hpp> +#include "../../OrthancFramework/Sources/FileStorage/StorageAccessor.h" + namespace Orthanc { class DicomInstanceToStore; @@ -66,25 +68,6 @@ friend class ServerIndex; // To access "RemoveFile()" public: - class ILookupVisitor : public boost::noncopyable - { - public: - virtual ~ILookupVisitor() - { - } - - virtual bool IsDicomAsJsonNeeded() const = 0; - - virtual void MarkAsComplete() = 0; - - // NB: "dicomAsJson" must *not* be deleted, and can be NULL if - // "!IsDicomAsJsonNeeded()" - virtual void Visit(const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson) = 0; - }; - struct StoreResult { private: @@ -250,6 +233,7 @@ std::unique_ptr<SharedArchive> queryRetrieveArchive_; std::string defaultLocalAet_; + RetrieveMethod defaultDicomRetrieveMethod_; OrthancHttpHandler httpHandler_; bool saveJobs_; FindStorageAccessMode findStorageAccessMode_; @@ -274,9 +258,10 @@ // New in Orthanc 1.9.0 DicomTransferSyntax preferredTransferSyntax_; - boost::mutex dynamicOptionsMutex_; + mutable boost::mutex dynamicOptionsMutex_; bool isUnknownSopClassAccepted_; std::set<DicomTransferSyntax> acceptedTransferSyntaxes_; + std::list<std::string> acceptedSopClasses_; // ordered; the most 120 common ones first bool readOnly_; StoreResult StoreAfterTranscoding(std::string& resultPublicId, @@ -324,7 +309,8 @@ IStorageArea& area, bool unitTesting, size_t maxCompletedJobs, - bool readOnly); + bool readOnly, + unsigned int maxConcurrentDcmtkTranscoder); ~ServerContext(); @@ -377,11 +363,10 @@ bool isReconstruct = false); void AnswerAttachment(RestApiOutput& output, - const std::string& resourceId, - FileContentType content); + const FileInfo& fileInfo); - void ChangeAttachmentCompression(const std::string& resourceId, - ResourceType resourceType, + void ChangeAttachmentCompression(ResourceType level, + const std::string& resourceId, FileContentType attachmentType, CompressionType compression); @@ -413,13 +398,15 @@ // This method is for low-level operations on "/instances/.../attachments/..." void ReadAttachment(std::string& result, - int64_t& revision, - std::string& attachmentId, - const std::string& instancePublicId, - FileContentType content, + const FileInfo& attachment, bool uncompressIfNeeded, bool skipCache = false); + void ReadAttachmentRange(std::string& result, + const FileInfo& attachment, + const StorageAccessor::Range& range, + bool uncompressIfNeeded); + void SetStoreMD5ForAttachments(bool storeMD5); bool IsStoreMD5ForAttachments() const @@ -453,6 +440,11 @@ return defaultLocalAet_; } + RetrieveMethod GetDefaultDicomRetrieveMethod() const + { + return defaultDicomRetrieveMethod_; + } + LuaScripting& GetLuaScripting() { return mainLua_; @@ -470,23 +462,6 @@ return (level == ResourceType_Instance ? limitFindInstances_ : limitFindResults_); } - void Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, - LabelsConstraint labelsConstraint, - size_t since, - size_t limit); - - void Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - size_t since, - size_t limit) - { - Apply(visitor, lookup, queryLevel, std::set<std::string>(), LabelsConstraint_All, since, limit); - } - bool LookupOrReconstructMetadata(std::string& target, const std::string& publicId, ResourceType level, @@ -617,41 +592,21 @@ const std::string& GetDeidentifiedContent(const DicomElement& element) const; - void GetAcceptedTransferSyntaxes(std::set<DicomTransferSyntax>& syntaxes); + void GetAcceptedTransferSyntaxes(std::set<DicomTransferSyntax>& syntaxes) const; void SetAcceptedTransferSyntaxes(const std::set<DicomTransferSyntax>& syntaxes); - bool IsUnknownSopClassAccepted(); + void GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& syntaxes) const; + + void SetAcceptedSopClasses(const std::list<std::string>& acceptedSopClasses, + const std::set<std::string>& rejectedSopClasses); + + void GetAcceptedSopClasses(std::set<std::string>& sopClasses, size_t maxCount) const; + + bool IsUnknownSopClassAccepted() const; void SetUnknownSopClassAccepted(bool accepted); - bool ExpandResource(Json::Value& target, - const std::string& publicId, - ResourceType level, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess); - - bool ExpandResource(Json::Value& target, - const std::string& publicId, - const DicomMap& mainDicomTags, // optional: the main dicom tags for the resource (if already available) - const std::string& instanceId, // optional: the id of an instance for the resource - const Json::Value* dicomAsJson, // optional: the dicom-as-json for the resource - ResourceType level, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess); - - bool ExpandResource(ExpandedResource& target, - const std::string& publicId, - const DicomMap& mainDicomTags, // optional: the main dicom tags for the resource (if already available) - const std::string& instanceId, // optional: the id of an instance for the resource - const Json::Value* dicomAsJson, // optional: the dicom-as-json for the resource - ResourceType level, - const std::set<DicomTag>& requestedTags, - ExpandResourceFlags expandFlags, - bool allowStorageAccess); - FindStorageAccessMode GetFindStorageAccessMode() const { return findStorageAccessMode_;
--- a/OrthancServer/Sources/ServerEnumerations.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerEnumerations.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -623,6 +623,10 @@ { return ResponseContentFlags_MainDicomTags; } + else if (value == "RequestedTags") + { + return ResponseContentFlags_RequestedTags; + } else if (value == "Metadata") { return ResponseContentFlags_Metadata;
--- a/OrthancServer/Sources/ServerEnumerations.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerEnumerations.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -137,6 +137,8 @@ ResponseContentFlags_Labels = (1 << 11), ResponseContentFlags_IsStable = (1 << 12), + ResponseContentFlags_INTERNAL_CountResources = (1 << 30), + // Some predefined combinations ResponseContentFlags_ExpandTrue = (ResponseContentFlags_ID | ResponseContentFlags_Type | @@ -250,9 +252,11 @@ Warnings_None, Warnings_001_TagsBeingReadFromStorage, Warnings_002_InconsistentDicomTagsInDb, - Warnings_003_DecoderFailure, // new in Orthanc 1.12.5 - Warnings_004_NoMainDicomTagsSignature, // new in Orthanc 1.12.5 - Warnings_005_RequestingTagFromLowerResourceLevel // new in Orthanc 1.12.5 + Warnings_003_DecoderFailure, // new in Orthanc 1.12.5 + Warnings_004_NoMainDicomTagsSignature, // new in Orthanc 1.12.5 + Warnings_005_RequestingTagFromLowerResourceLevel, // new in Orthanc 1.12.5 + Warnings_006_RequestingTagFromMetaHeader, // new in Orthanc 1.12.5 + Warnings_007_MissingRequestedTagsNotReadFromDisk // new in Orthanc 1.12.5 };
--- a/OrthancServer/Sources/ServerIndex.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerIndex.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -273,40 +273,6 @@ } }; - void ServerIndex::UpdateStatisticsThread(ServerIndex* that, - unsigned int threadSleepGranularityMilliseconds) - { - Logging::SetCurrentThreadName("DB-STATS"); - - static const unsigned int SLEEP_SECONDS = 10; - - if (threadSleepGranularityMilliseconds > 1000) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - LOG(INFO) << "Starting the update statistics thread (sleep = " << SLEEP_SECONDS << " seconds)"; - - unsigned int count = 0; - unsigned int countThreshold = (1000 * SLEEP_SECONDS) / threadSleepGranularityMilliseconds; - - while (!that->done_) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(threadSleepGranularityMilliseconds)); - count++; - - if (count >= countThreshold) - { - uint64_t diskSize, uncompressedSize, countPatients, countStudies, countSeries, countInstances; - that->GetGlobalStatistics(diskSize, uncompressedSize, countPatients, countStudies, countSeries, countInstances); - - count = 0; - } - } - - LOG(INFO) << "Stopping the update statistics thread"; - } - void ServerIndex::FlushThread(ServerIndex* that, unsigned int threadSleepGranularityMilliseconds) { @@ -384,21 +350,6 @@ } } - // For some DB plugins that implements the UpdateAndGetStatistics function, updating - // the statistics can take quite some time if you have not done it for a long time - // -> make sure they are updated at regular interval - if (GetDatabaseCapabilities().HasUpdateAndGetStatistics()) - { - if (readOnly) - { - LOG(WARNING) << "READ-ONLY SYSTEM: not starting the UpdateStatisticsThread"; - } - else - { - updateStatisticsThread_ = boost::thread(UpdateStatisticsThread, this, threadSleepGranularityMilliseconds); - } - } - if (readOnly) { LOG(WARNING) << "READ-ONLY SYSTEM: not starting the unstable resources monitor thread"; @@ -432,11 +383,6 @@ flushThread_.join(); } - if (updateStatisticsThread_.joinable()) - { - updateStatisticsThread_.join(); - } - if (unstableResourcesMonitorThread_.joinable()) { unstableResourcesMonitorThread_.join();
--- a/OrthancServer/Sources/ServerIndex.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerIndex.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -42,7 +42,6 @@ bool done_; boost::mutex monitoringMutex_; boost::thread flushThread_; - boost::thread updateStatisticsThread_; boost::thread unstableResourcesMonitorThread_; LeastRecentlyUsedIndex<std::pair<ResourceType, int64_t>, UnstableResourcePayload> unstableResources_; @@ -55,9 +54,6 @@ static void FlushThread(ServerIndex* that, unsigned int threadSleep); - static void UpdateStatisticsThread(ServerIndex* that, - unsigned int threadSleep); - static void UnstableResourcesMonitorThread(ServerIndex* that, unsigned int threadSleep);
--- a/OrthancServer/Sources/ServerIndexChange.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerIndexChange.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -31,8 +31,10 @@ #include "../../../OrthancFramework/Sources/Logging.h" #include "../../../OrthancFramework/Sources/OrthancException.h" #include "../../../OrthancFramework/Sources/MultiThreading/Semaphore.h" +#include "../../../OrthancFramework/Sources/SerializationToolbox.h" #include "../OrthancConfiguration.h" #include "../ServerContext.h" +#include "../SimpleInstanceOrdering.h" #include <stdio.h> #include <boost/range/algorithm/count.hpp> @@ -98,7 +100,7 @@ { } - virtual void PrepareDicom(const std::string& instanceId) + virtual void PrepareDicom(const std::string& instanceId, const FileInfo& fileInfo) { } @@ -127,7 +129,7 @@ return false; } - virtual void GetDicom(std::string& dicom, const std::string& instanceId) = 0; + virtual void GetDicom(std::string& dicom, const std::string& instanceId, const FileInfo& fileInfo) = 0; virtual void Clear() { @@ -142,9 +144,9 @@ { } - virtual void GetDicom(std::string& dicom, const std::string& instanceId) ORTHANC_OVERRIDE + virtual void GetDicom(std::string& dicom, const std::string& instanceId, const FileInfo& fileInfo) ORTHANC_OVERRIDE { - context_.ReadDicom(dicom, instanceId); + context_.ReadAttachment(dicom, fileInfo, true); if (transcode_) { @@ -158,21 +160,25 @@ } }; - class InstanceId : public Orthanc::IDynamicObject + class InstanceToPreload : public Orthanc::IDynamicObject { private: std::string id_; + FileInfo fileInfo_; public: - explicit InstanceId(const std::string& id) : id_(id) + explicit InstanceToPreload(const std::string& id, const FileInfo& fileInfo) : + id_(id), + fileInfo_(fileInfo) { } - virtual ~InstanceId() ORTHANC_OVERRIDE + virtual ~InstanceToPreload() ORTHANC_OVERRIDE { } - std::string GetId() const {return id_;}; + const std::string& GetId() const {return id_;}; + const FileInfo& GetFileInfo() const {return fileInfo_;}; }; class ArchiveJob::ThreadedInstanceLoader : public ArchiveJob::InstanceLoader @@ -229,8 +235,8 @@ while (true) { - std::unique_ptr<InstanceId> instanceId(dynamic_cast<InstanceId*>(that->instancesToPreload_.Dequeue(0))); - if (instanceId.get() == NULL) // that's the signal to exit the thread + std::unique_ptr<InstanceToPreload> instanceToPreload(dynamic_cast<InstanceToPreload*>(that->instancesToPreload_.Dequeue(0))); + if (instanceToPreload.get() == NULL) // that's the signal to exit the thread { return; } @@ -241,12 +247,12 @@ try { boost::shared_ptr<std::string> dicomContent(new std::string()); - that->context_.ReadDicom(*dicomContent, instanceId->GetId()); + that->context_.ReadAttachment(*dicomContent, instanceToPreload->GetFileInfo(), true); if (that->transcode_) { boost::shared_ptr<std::string> transcodedDicom(new std::string()); - if (that->TranscodeDicom(*transcodedDicom, *dicomContent, instanceId->GetId())) + if (that->TranscodeDicom(*transcodedDicom, *dicomContent, instanceToPreload->GetId())) { dicomContent = transcodedDicom; } @@ -254,7 +260,7 @@ { boost::mutex::scoped_lock lock(that->availableInstancesMutex_); - that->availableInstances_[instanceId->GetId()] = dicomContent; + that->availableInstances_[instanceToPreload->GetId()] = dicomContent; } that->availableInstancesSemaphore_.Release(); @@ -263,18 +269,18 @@ { boost::mutex::scoped_lock lock(that->availableInstancesMutex_); // store a NULL result to notify that we could not read the instance - that->availableInstances_[instanceId->GetId()] = boost::shared_ptr<std::string>(); + that->availableInstances_[instanceToPreload->GetId()] = boost::shared_ptr<std::string>(); that->availableInstancesSemaphore_.Release(); } } } - virtual void PrepareDicom(const std::string& instanceId) ORTHANC_OVERRIDE + virtual void PrepareDicom(const std::string& instanceId, const FileInfo& fileInfo) ORTHANC_OVERRIDE { - instancesToPreload_.Enqueue(new InstanceId(instanceId)); + instancesToPreload_.Enqueue(new InstanceToPreload(instanceId, fileInfo)); } - virtual void GetDicom(std::string& dicom, const std::string& instanceId) ORTHANC_OVERRIDE + virtual void GetDicom(std::string& dicom, const std::string& instanceId, const FileInfo& fileInfo) ORTHANC_OVERRIDE { while (true) { @@ -284,6 +290,8 @@ boost::shared_ptr<std::string> dicomContent; { + boost::mutex::scoped_lock lock(availableInstancesMutex_); + if (availableInstances_.find(instanceId) != availableInstances_.end()) { // this is the instance we were waiting for @@ -366,7 +374,7 @@ { case ResourceType_Patient: return ArchiveResourceType_Patient; - case ArchiveResourceType_Study: + case ResourceType_Study: return ArchiveResourceType_PatientInfoFromStudy; case ResourceType_Series: return ArchiveResourceType_Series; @@ -506,7 +514,8 @@ virtual void Close() = 0; virtual void AddInstance(const std::string& instanceId, - uint64_t uncompressedSize) = 0; + uint32_t index, + const FileInfo& fileInfo) = 0; }; @@ -516,12 +525,15 @@ struct Instance { std::string id_; - uint64_t uncompressedSize_; + uint32_t index_; + FileInfo fileInfo_; Instance(const std::string& id, - uint64_t uncompressedSize) : + uint32_t index, + const FileInfo& fileInfo) : id_(id), - uncompressedSize_(uncompressedSize) + index_(index), + fileInfo_(fileInfo) { } }; @@ -534,22 +546,18 @@ std::list<Instance> instances_; // Only at instance level - void AddResourceToExpand(ServerIndex& index, - const std::string& id) + void AddResourceToExpand(const std::string& id) { - if (level_ == ArchiveResourceType_Instance) - { - FileInfo tmp; - int64_t revision; // ignored - if (index.LookupAttachment(tmp, revision, id, FileContentType_Dicom)) - { - instances_.push_back(Instance(id, tmp.GetUncompressedSize())); - } - } - else - { - resources_[id] = NULL; - } + assert(level_ != ArchiveResourceType_Instance); + resources_[id] = NULL; + } + + void AddInstance(const std::string& id, + uint32_t indexInSeries, + const FileInfo& fileInfo) + { + assert(level_ == ArchiveResourceType_Instance); + instances_.push_back(Instance(id, indexInSeries, fileInfo)); } @@ -577,7 +585,20 @@ if (level_ == ArchiveResourceType_Instance) { - AddResourceToExpand(index, id); + std::string strIndexInSeries; + uint32_t indexInSeries = 0; + FileInfo fileInfo; + int64_t revisionNotUsed; + + if (index.LookupMetadata(strIndexInSeries, id, ResourceType_Instance, MetadataType_Instance_IndexInSeries)) + { + SerializationToolbox::ParseUnsignedInteger32(indexInSeries, strIndexInSeries); + } + + if (index.LookupAttachment(fileInfo, revisionNotUsed, ResourceType_Instance, id, FileContentType_Dicom)) + { + AddInstance(id, indexInSeries, fileInfo); + } } else if (resource.GetLevel() == GetResourceLevel(level_)) { @@ -620,16 +641,31 @@ { if (it->second == NULL) { - // This is resource is marked for expansion - std::list<std::string> children; - index.GetChildren(children, it->first); - + // This resource is marked for expansion std::unique_ptr<ArchiveIndex> child(new ArchiveIndex(GetChildResourceType(level_))); - for (std::list<std::string>::const_iterator - it2 = children.begin(); it2 != children.end(); ++it2) + if (level_ == ArchiveResourceType_Series) { - child->AddResourceToExpand(index, *it2); + // Instances ordering is important ! + // From 1.12.6, when possible, the id in the filename will match the index in series. + // Only if there are duplicate index in series, we'll use a simple counter + SimpleInstanceOrdering orderedInstances(index, it->first); + + for (size_t i = 0; i < orderedInstances.GetInstancesCount(); ++i) + { + child->AddInstance(orderedInstances.GetInstanceId(i), orderedInstances.GetInstanceIndexInSeries(i), orderedInstances.GetInstanceFileInfo(i)); + } + } + else + { + std::list<std::string> children; + index.GetChildren(children, GetResourceLevel(level_), it->first); + + for (std::list<std::string>::const_iterator + it2 = children.begin(); it2 != children.end(); ++it2) + { + child->AddResourceToExpand(*it2); + } } it->second = child.release(); @@ -648,7 +684,7 @@ for (std::list<Instance>::const_iterator it = instances_.begin(); it != instances_.end(); ++it) { - visitor.AddInstance(it->id_, it->uncompressedSize_); + visitor.AddInstance(it->id_, it->index_, it->fileInfo_); } } else @@ -683,6 +719,7 @@ Type type_; std::string filename_; std::string instanceId_; + FileInfo fileInfo_; public: explicit Command(Type type) : @@ -701,10 +738,12 @@ Command(Type type, const std::string& filename, - const std::string& instanceId) : + const std::string& instanceId, + const FileInfo& fileInfo) : type_(type), filename_(filename), - instanceId_(instanceId) + instanceId_(instanceId), + fileInfo_(fileInfo) { assert(type_ == Type_WriteInstance); } @@ -733,7 +772,7 @@ try { - instanceLoader.GetDicom(content, instanceId_); + instanceLoader.GetDicom(content, instanceId_, fileInfo_); } catch (OrthancException& e) { @@ -858,12 +897,12 @@ void AddWriteInstance(const std::string& filename, const std::string& instanceId, - uint64_t uncompressedSize) + const FileInfo& fileInfo) { - instanceLoader_.PrepareDicom(instanceId); - commands_.push_back(new Command(Type_WriteInstance, filename, instanceId)); + instanceLoader_.PrepareDicom(instanceId, fileInfo); + commands_.push_back(new Command(Type_WriteInstance, filename, instanceId, fileInfo)); instancesCount_ ++; - uncompressedSize_ += uncompressedSize; + uncompressedSize_ += fileInfo.GetUncompressedSize(); } bool IsZip64() const @@ -982,13 +1021,13 @@ } virtual void AddInstance(const std::string& instanceId, - uint64_t uncompressedSize) ORTHANC_OVERRIDE + uint32_t index, + const FileInfo& fileInfo) ORTHANC_OVERRIDE { char filename[24]; - snprintf(filename, sizeof(filename) - 1, instanceFormat_, counter_); - counter_ ++; + snprintf(filename, sizeof(filename) - 1, instanceFormat_, index); - commands_.AddWriteInstance(filename, instanceId, uncompressedSize); + commands_.AddWriteInstance(filename, instanceId, fileInfo); } }; @@ -1016,13 +1055,14 @@ } virtual void AddInstance(const std::string& instanceId, - uint64_t uncompressedSize) ORTHANC_OVERRIDE + uint32_t indexNotUsed, + const FileInfo& fileInfo) ORTHANC_OVERRIDE { // "DICOM restricts the filenames on DICOM media to 8 // characters (some systems wrongly use 8.3, but this does not // conform to the standard)." std::string filename = "IM" + boost::lexical_cast<std::string>(counter_); - commands_.AddWriteInstance(filename, instanceId, uncompressedSize); + commands_.AddWriteInstance(filename, instanceId, fileInfo); counter_ ++; } @@ -1478,7 +1518,7 @@ } - float ArchiveJob::GetProgress() + float ArchiveJob::GetProgress() const { if (writer_.get() == NULL || writer_->GetStepsCount() == 0) @@ -1493,7 +1533,7 @@ } - void ArchiveJob::GetJobType(std::string& target) + void ArchiveJob::GetJobType(std::string& target) const { if (isMedia_) { @@ -1506,7 +1546,7 @@ } - void ArchiveJob::GetPublicContent(Json::Value& value) + void ArchiveJob::GetPublicContent(Json::Value& value) const { value = Json::objectValue; value[KEY_DESCRIPTION] = description_;
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -107,13 +107,13 @@ virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; - virtual float GetProgress() ORTHANC_OVERRIDE; + virtual float GetProgress() const ORTHANC_OVERRIDE; - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE; + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE; - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE + virtual bool Serialize(Json::Value& value) const ORTHANC_OVERRIDE { return false; // Cannot serialize this kind of job }
--- a/OrthancServer/Sources/ServerJobs/CleaningInstancesJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/CleaningInstancesJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -83,7 +83,7 @@ } - bool CleaningInstancesJob::Serialize(Json::Value& target) + bool CleaningInstancesJob::Serialize(Json::Value& target) const { if (!SetOfInstancesJob::Serialize(target)) {
--- a/OrthancServer/Sources/ServerJobs/CleaningInstancesJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/CleaningInstancesJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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,7 +62,7 @@ void SetKeepSource(bool keep); - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; virtual void Start() ORTHANC_OVERRIDE; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/ServerJobs/DicomGetScuJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,121 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "DicomGetScuJob.h" + +#include "../../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" +#include "../../../OrthancFramework/Sources/SerializationToolbox.h" +#include "../ServerContext.h" +#include <dcmtk/dcmnet/dimse.h> +#include <algorithm> + +static const char* const LOCAL_AET = "LocalAet"; +static const char* const QUERY = "Query"; +static const char* const QUERY_FORMAT = "QueryFormat"; // New in 1.9.5 +static const char* const REMOTE = "Remote"; +static const char* const TIMEOUT = "Timeout"; + +namespace Orthanc +{ + + + static uint16_t InstanceReceivedHandler(void* callbackContext, + DcmDataset& dataset, + const std::string& remoteAet, + const std::string& remoteIp, + const std::string& calledAet) + { + // this code is equivalent to OrthancStoreRequestHandler + ServerContext* context = reinterpret_cast<ServerContext*>(callbackContext); + + std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromDcmDataset(dataset)); + + if (toStore->GetBufferSize() > 0) + { + toStore->SetOrigin(DicomInstanceOrigin::FromDicomProtocol + (remoteIp.c_str(), remoteAet.c_str(), calledAet.c_str())); + + std::string id; + ServerContext::StoreResult result = context->Store(id, *toStore, StoreInstanceMode_Default); + return result.GetCStoreStatusCode(); + } + + return STATUS_STORE_Error_CannotUnderstand; + } + + void DicomGetScuJob::Retrieve(const DicomMap& findAnswer) + { + if (connection_.get() == NULL) + { + std::set<std::string> sopClassesToPropose; + std::set<std::string> acceptedSopClasses; + std::list<DicomTransferSyntax> proposedTransferSyntaxes; + + if (sopClassesFromResourcesToRetrieve_.size() > 0) + { + context_.GetAcceptedSopClasses(acceptedSopClasses, 0); + + // keep the sop classes from the resources to retrieve only if they are accepted by Orthanc + Toolbox::GetIntersection(sopClassesToPropose, sopClassesFromResourcesToRetrieve_, acceptedSopClasses); + } + else + { + // when we don't know what SOP Classes to use, we include the 120 most common SOP Classes because + // there are only 128 presentation contexts available + context_.GetAcceptedSopClasses(sopClassesToPropose, 120); + } + + if (sopClassesToPropose.size() == 0) + { + throw OrthancException(ErrorCode_NoPresentationContext, "Cannot perform C-Get, no SOPClassUID have been accepted by Orthanc."); + } + + context_.GetProposedStorageTransferSyntaxes(proposedTransferSyntaxes); + + connection_.reset(new DicomControlUserConnection(parameters_, + ScuOperationFlags_Get, + sopClassesToPropose, + proposedTransferSyntaxes)); + } + + connection_->SetProgressListener(this); + connection_->Get(findAnswer, InstanceReceivedHandler, &context_); + } + + void DicomGetScuJob::AddFindAnswer(const DicomMap& answer) + { + DicomRetrieveScuBaseJob::AddFindAnswer(answer); + + std::set<std::string> sopClassesInStudy; + if (answer.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY) + && answer.LookupStringValues(sopClassesInStudy, DICOM_TAG_SOP_CLASSES_IN_STUDY, false)) + { + for (std::set<std::string>::const_iterator it = sopClassesInStudy.begin(); it != sopClassesInStudy.end(); ++it) + { + sopClassesFromResourcesToRetrieve_.insert(*it); + } + } + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/ServerJobs/DicomGetScuJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,60 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../../../OrthancFramework/Sources/Compatibility.h" +#include "../../../OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h" +#include "DicomRetrieveScuBaseJob.h" +#include "../QueryRetrieveHandler.h" + +namespace Orthanc +{ + class ServerContext; + + class DicomGetScuJob : public DicomRetrieveScuBaseJob + { + private: + std::set<std::string> sopClassesFromResourcesToRetrieve_; + + virtual void Retrieve(const DicomMap& findAnswer) ORTHANC_OVERRIDE; + + public: + explicit DicomGetScuJob(ServerContext& context) : + DicomRetrieveScuBaseJob(context) + { + } + + DicomGetScuJob(ServerContext& context, + const Json::Value& serialized); + + + virtual void AddFindAnswer(const DicomMap &answer) ORTHANC_OVERRIDE; + + + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE + { + target = "DicomGetScu"; + } + }; +}
--- a/OrthancServer/Sources/ServerJobs/DicomModalityStoreJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/DicomModalityStoreJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -242,7 +242,7 @@ } - void DicomModalityStoreJob::GetPublicContent(Json::Value& value) + void DicomModalityStoreJob::GetPublicContent(Json::Value& value) const { SetOfInstancesJob::GetPublicContent(value); @@ -281,7 +281,7 @@ } - bool DicomModalityStoreJob::Serialize(Json::Value& target) + bool DicomModalityStoreJob::Serialize(Json::Value& target) const { if (!SetOfInstancesJob::Serialize(target)) {
--- a/OrthancServer/Sources/ServerJobs/DicomModalityStoreJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/DicomModalityStoreJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -88,14 +88,14 @@ virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = "DicomModalityStore"; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; virtual void Reset() ORTHANC_OVERRIDE;
--- a/OrthancServer/Sources/ServerJobs/DicomMoveScuJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/DicomMoveScuJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -36,123 +36,21 @@ namespace Orthanc { - class DicomMoveScuJob::Command : public SetOfCommandsJob::ICommand - { - private: - DicomMoveScuJob& that_; - std::unique_ptr<DicomMap> findAnswer_; - public: - Command(DicomMoveScuJob& that, - const DicomMap& findAnswer) : - that_(that), - findAnswer_(findAnswer.Clone()) - { - } - - virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE - { - that_.Retrieve(*findAnswer_); - return true; - } - - virtual void Serialize(Json::Value& target) const ORTHANC_OVERRIDE - { - findAnswer_->Serialize(target); - } - }; - - - class DicomMoveScuJob::Unserializer : - public SetOfCommandsJob::ICommandUnserializer - { - private: - DicomMoveScuJob& that_; - - public: - explicit Unserializer(DicomMoveScuJob& that) : - that_(that) - { - } - - virtual ICommand* Unserialize(const Json::Value& source) const ORTHANC_OVERRIDE - { - DicomMap findAnswer; - findAnswer.Unserialize(source); - return new Command(that_, findAnswer); - } - }; void DicomMoveScuJob::Retrieve(const DicomMap& findAnswer) { if (connection_.get() == NULL) { - connection_.reset(new DicomControlUserConnection(parameters_)); + connection_.reset(new DicomControlUserConnection(parameters_, ScuOperationFlags_Move)); } + connection_->SetProgressListener(this); connection_->Move(targetAet_, findAnswer); } - static void AddToQuery(DicomFindAnswers& query, - const DicomMap& item) - { - query.Add(item); - - /** - * Compatibility with Orthanc <= 1.9.4: Remove the - * "SpecificCharacterSet" (0008,0005) tag that is automatically - * added if creating a ParsedDicomFile object from a DicomMap. - **/ - query.GetAnswer(query.GetSize() - 1).Remove(DICOM_TAG_SPECIFIC_CHARACTER_SET); - } - - // this method is used to implement the retrieve part of a Q&R - // it keeps only the main dicom tags from the C-Find answer - void DicomMoveScuJob::AddFindAnswer(const DicomMap& answer) - { - DicomMap item; - item.CopyTagIfExists(answer, DICOM_TAG_QUERY_RETRIEVE_LEVEL); - item.CopyTagIfExists(answer, DICOM_TAG_PATIENT_ID); - item.CopyTagIfExists(answer, DICOM_TAG_STUDY_INSTANCE_UID); - item.CopyTagIfExists(answer, DICOM_TAG_SERIES_INSTANCE_UID); - item.CopyTagIfExists(answer, DICOM_TAG_SOP_INSTANCE_UID); - item.CopyTagIfExists(answer, DICOM_TAG_ACCESSION_NUMBER); - AddToQuery(query_, item); - - AddCommand(new Command(*this, answer)); - } - - // this method is used to implement a C-Move - // it keeps all tags from the C-Move query - void DicomMoveScuJob::AddQuery(const DicomMap& query) - { - AddToQuery(query_, query); - AddCommand(new Command(*this, query)); - } - - void DicomMoveScuJob::AddFindAnswer(QueryRetrieveHandler& query, - size_t i) - { - DicomMap answer; - query.GetAnswer(answer, i); - AddFindAnswer(answer); - } - - - void DicomMoveScuJob::SetLocalAet(const std::string& aet) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetLocalApplicationEntityTitle(aet); - } - } - void DicomMoveScuJob::SetTargetAet(const std::string& aet) { @@ -167,109 +65,33 @@ } - void DicomMoveScuJob::SetRemoteModality(const RemoteModalityParameters& remote) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetRemoteModality(remote); - } - } - void DicomMoveScuJob::SetTimeout(uint32_t seconds) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetTimeout(seconds); - } - } - - - void DicomMoveScuJob::Stop(JobStopReason reason) - { - connection_.reset(); - } - - - void DicomMoveScuJob::SetQueryFormat(DicomToJsonFormat format) + void DicomMoveScuJob::GetPublicContent(Json::Value& value) const { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - queryFormat_ = format; - } - } + DicomRetrieveScuBaseJob::GetPublicContent(value); - - void DicomMoveScuJob::GetPublicContent(Json::Value& value) - { - SetOfCommandsJob::GetPublicContent(value); - - value[LOCAL_AET] = parameters_.GetLocalApplicationEntityTitle(); - value["RemoteAet"] = parameters_.GetRemoteModality().GetApplicationEntityTitle(); - - value[QUERY] = Json::objectValue; - query_.ToJson(value[QUERY], queryFormat_); + value[TARGET_AET] = targetAet_; } DicomMoveScuJob::DicomMoveScuJob(ServerContext& context, const Json::Value& serialized) : - SetOfCommandsJob(new Unserializer(*this), serialized), - context_(context), - parameters_(DicomAssociationParameters::UnserializeJob(serialized)), - targetAet_(SerializationToolbox::ReadString(serialized, TARGET_AET)), - query_(true), - queryFormat_(DicomToJsonFormat_Short) + DicomRetrieveScuBaseJob(context, serialized), + targetAet_(SerializationToolbox::ReadString(serialized, TARGET_AET)) { - if (serialized.isMember(QUERY)) - { - const Json::Value& query = serialized[QUERY]; - if (query.type() == Json::arrayValue) - { - for (Json::Value::ArrayIndex i = 0; i < query.size(); i++) - { - DicomMap item; - FromDcmtkBridge::FromJson(item, query[i]); - AddToQuery(query_, item); - } - } - } - - if (serialized.isMember(QUERY_FORMAT)) - { - queryFormat_ = StringToDicomToJsonFormat(SerializationToolbox::ReadString(serialized, QUERY_FORMAT)); - } } - bool DicomMoveScuJob::Serialize(Json::Value& target) + bool DicomMoveScuJob::Serialize(Json::Value& target) const { - if (!SetOfCommandsJob::Serialize(target)) + if (!DicomRetrieveScuBaseJob::Serialize(target)) { return false; } else { - parameters_.SerializeJob(target); target[TARGET_AET] = targetAet_; - - // "Short" is for compatibility with Orthanc <= 1.9.4 - target[QUERY] = Json::objectValue; - query_.ToJson(target[QUERY], DicomToJsonFormat_Short); - - target[QUERY_FORMAT] = EnumerationToString(queryFormat_); return true; }
--- a/OrthancServer/Sources/ServerJobs/DicomMoveScuJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/DicomMoveScuJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -25,7 +25,8 @@ #include "../../../OrthancFramework/Sources/Compatibility.h" #include "../../../OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h" -#include "../../../OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h" +// #include "../../../OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h" +#include "DicomRetrieveScuBaseJob.h" #include "../QueryRetrieveHandler.h" @@ -33,51 +34,22 @@ { class ServerContext; - class DicomMoveScuJob : public SetOfCommandsJob + class DicomMoveScuJob : public DicomRetrieveScuBaseJob { private: - class Command; - class Unserializer; + std::string targetAet_; - ServerContext& context_; - DicomAssociationParameters parameters_; - std::string targetAet_; - DicomFindAnswers query_; - DicomToJsonFormat queryFormat_; // New in 1.9.5 - - std::unique_ptr<DicomControlUserConnection> connection_; - - void Retrieve(const DicomMap& findAnswer); + virtual void Retrieve(const DicomMap& findAnswer) ORTHANC_OVERRIDE; public: explicit DicomMoveScuJob(ServerContext& context) : - context_(context), - query_(false /* this is not for worklists */), - queryFormat_(DicomToJsonFormat_Short) + DicomRetrieveScuBaseJob(context) { } DicomMoveScuJob(ServerContext& context, const Json::Value& serialized); - void AddFindAnswer(const DicomMap& answer); - - void AddQuery(const DicomMap& query); - - void AddFindAnswer(QueryRetrieveHandler& query, - size_t i); - - const DicomAssociationParameters& GetParameters() const - { - return parameters_; - } - - void SetLocalAet(const std::string& aet); - - void SetRemoteModality(const RemoteModalityParameters& remote); - - void SetTimeout(uint32_t timeout); - const std::string& GetTargetAet() const { return targetAet_; @@ -85,22 +57,13 @@ void SetTargetAet(const std::string& aet); - void SetQueryFormat(DicomToJsonFormat format); - - DicomToJsonFormat GetQueryFormat() const - { - return queryFormat_; - } - - virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; - - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = "DicomMoveScu"; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,248 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "DicomGetScuJob.h" + +#include "../../../OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h" +#include "../../../OrthancFramework/Sources/SerializationToolbox.h" +#include "../ServerContext.h" +#include <dcmtk/dcmnet/dimse.h> +#include <algorithm> +#include "../../../OrthancFramework/Sources/Logging.h" + +static const char* const LOCAL_AET = "LocalAet"; +static const char* const QUERY = "Query"; +static const char* const QUERY_FORMAT = "QueryFormat"; // New in 1.9.5 +static const char* const REMOTE = "Remote"; +static const char* const TIMEOUT = "Timeout"; + +namespace Orthanc +{ + + static void AddToQuery(DicomFindAnswers& query, + const DicomMap& item) + { + query.Add(item); + + /** + * Compatibility with Orthanc <= 1.9.4: Remove the + * "SpecificCharacterSet" (0008,0005) tag that is automatically + * added if creating a ParsedDicomFile object from a DicomMap. + **/ + query.GetAnswer(query.GetSize() - 1).Remove(DICOM_TAG_SPECIFIC_CHARACTER_SET); + } + + // this method is used to implement the retrieve part of a Q&R + // it keeps only the main dicom tags from the C-Find answer + void DicomRetrieveScuBaseJob::AddFindAnswer(const DicomMap& answer) + { + DicomMap item; + item.CopyTagIfExists(answer, DICOM_TAG_QUERY_RETRIEVE_LEVEL); + item.CopyTagIfExists(answer, DICOM_TAG_PATIENT_ID); + item.CopyTagIfExists(answer, DICOM_TAG_STUDY_INSTANCE_UID); + item.CopyTagIfExists(answer, DICOM_TAG_SERIES_INSTANCE_UID); + item.CopyTagIfExists(answer, DICOM_TAG_SOP_INSTANCE_UID); + item.CopyTagIfExists(answer, DICOM_TAG_ACCESSION_NUMBER); + AddToQuery(query_, item); + + AddCommand(new Command(*this, answer)); + } + + void DicomRetrieveScuBaseJob::AddFindAnswer(QueryRetrieveHandler& query, + size_t i) + { + DicomMap answer; + query.GetAnswer(answer, i); + AddFindAnswer(answer); + } + + // this method is used to implement a C-Move + // it keeps all tags from the C-Move query + void DicomRetrieveScuBaseJob::AddQuery(const DicomMap& query) + { + AddToQuery(query_, query); + AddCommand(new Command(*this, query)); + } + + + void DicomRetrieveScuBaseJob::SetLocalAet(const std::string& aet) + { + if (IsStarted()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + parameters_.SetLocalApplicationEntityTitle(aet); + } + } + + + void DicomRetrieveScuBaseJob::SetRemoteModality(const RemoteModalityParameters& remote) + { + if (IsStarted()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + parameters_.SetRemoteModality(remote); + } + } + + + void DicomRetrieveScuBaseJob::SetTimeout(uint32_t seconds) + { + if (IsStarted()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + parameters_.SetTimeout(seconds); + } + } + + + void DicomRetrieveScuBaseJob::Stop(JobStopReason reason) + { + connection_.reset(); + } + + + void DicomRetrieveScuBaseJob::SetQueryFormat(DicomToJsonFormat format) + { + if (IsStarted()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + queryFormat_ = format; + } + } + + + void DicomRetrieveScuBaseJob::GetPublicContent(Json::Value& value) const + { + SetOfCommandsJob::GetPublicContent(value); + + value[LOCAL_AET] = parameters_.GetLocalApplicationEntityTitle(); + value["RemoteAet"] = parameters_.GetRemoteModality().GetApplicationEntityTitle(); + + value[QUERY] = Json::objectValue; + query_.ToJson(value[QUERY], queryFormat_); + } + + + DicomRetrieveScuBaseJob::DicomRetrieveScuBaseJob(ServerContext &context) : + context_(context), + query_(false /* this is not for worklists */), + queryFormat_(DicomToJsonFormat_Short), + nbRemainingSubOperations_(0), + nbCompletedSubOperations_(0), + nbFailedSubOperations_(0), + nbWarningSubOperations_(0) + { + } + + + DicomRetrieveScuBaseJob::DicomRetrieveScuBaseJob(ServerContext& context, + const Json::Value& serialized) : + SetOfCommandsJob(new Unserializer(*this), serialized), + context_(context), + parameters_(DicomAssociationParameters::UnserializeJob(serialized)), + query_(true), + queryFormat_(DicomToJsonFormat_Short), + nbRemainingSubOperations_(0), + nbCompletedSubOperations_(0), + nbFailedSubOperations_(0), + nbWarningSubOperations_(0) + { + if (serialized.isMember(QUERY)) + { + const Json::Value& query = serialized[QUERY]; + if (query.type() == Json::arrayValue) + { + for (Json::Value::ArrayIndex i = 0; i < query.size(); i++) + { + DicomMap item; + FromDcmtkBridge::FromJson(item, query[i]); + AddToQuery(query_, item); + } + } + } + + if (serialized.isMember(QUERY_FORMAT)) + { + queryFormat_ = StringToDicomToJsonFormat(SerializationToolbox::ReadString(serialized, QUERY_FORMAT)); + } + } + + + bool DicomRetrieveScuBaseJob::Serialize(Json::Value& target) const + { + if (!SetOfCommandsJob::Serialize(target)) + { + return false; + } + else + { + parameters_.SerializeJob(target); + + // "Short" is for compatibility with Orthanc <= 1.9.4 + target[QUERY] = Json::objectValue; + query_.ToJson(target[QUERY], DicomToJsonFormat_Short); + + target[QUERY_FORMAT] = EnumerationToString(queryFormat_); + + return true; + } + } + + void DicomRetrieveScuBaseJob::OnProgressUpdated(uint16_t nbRemainingSubOperations, + uint16_t nbCompletedSubOperations, + uint16_t nbFailedSubOperations, + uint16_t nbWarningSubOperations) + { + boost::mutex::scoped_lock lock(progressMutex_); + + nbRemainingSubOperations_ = nbRemainingSubOperations; + nbCompletedSubOperations_ = nbCompletedSubOperations; + nbFailedSubOperations_ = nbFailedSubOperations; + nbWarningSubOperations_ = nbWarningSubOperations; + } + + float DicomRetrieveScuBaseJob::GetProgress() const + { + boost::mutex::scoped_lock lock(progressMutex_); + + uint32_t totalOperations = nbRemainingSubOperations_ + nbCompletedSubOperations_ + nbFailedSubOperations_ + nbWarningSubOperations_; + if (totalOperations == 0) + { + return 0.0f; + } + + return float(nbCompletedSubOperations_ + nbFailedSubOperations_ + nbWarningSubOperations_) / float(totalOperations); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/ServerJobs/DicomRetrieveScuBaseJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,149 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#pragma once + +#include "../../../OrthancFramework/Sources/Compatibility.h" +#include "../../../OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h" +#include "../../../OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h" +#include <boost/thread/mutex.hpp> + +#include "../QueryRetrieveHandler.h" + +namespace Orthanc +{ + class ServerContext; + + class DicomRetrieveScuBaseJob : public SetOfCommandsJob, public DicomControlUserConnection::IProgressListener + { + protected: + class Command : public SetOfCommandsJob::ICommand + { + private: + DicomRetrieveScuBaseJob &that_; + std::unique_ptr<DicomMap> findAnswer_; + + public: + Command(DicomRetrieveScuBaseJob &that, + const DicomMap &findAnswer) : + that_(that), + findAnswer_(findAnswer.Clone()) + { + } + + virtual bool Execute(const std::string &jobId) ORTHANC_OVERRIDE + { + that_.Retrieve(*findAnswer_); + return true; + } + + virtual void Serialize(Json::Value &target) const ORTHANC_OVERRIDE + { + findAnswer_->Serialize(target); + } + }; + + class Unserializer : public SetOfCommandsJob::ICommandUnserializer + { + protected: + DicomRetrieveScuBaseJob &that_; + + public: + explicit Unserializer(DicomRetrieveScuBaseJob &that) : + that_(that) + { + } + + virtual ICommand *Unserialize(const Json::Value &source) const ORTHANC_OVERRIDE + { + DicomMap findAnswer; + findAnswer.Unserialize(source); + return new Command(that_, findAnswer); + } + }; + + ServerContext &context_; + DicomAssociationParameters parameters_; + DicomFindAnswers query_; + DicomToJsonFormat queryFormat_; // New in 1.9.5 + + std::unique_ptr<DicomControlUserConnection> connection_; + + mutable boost::mutex progressMutex_; + uint16_t nbRemainingSubOperations_; + uint16_t nbCompletedSubOperations_; + uint16_t nbFailedSubOperations_; + uint16_t nbWarningSubOperations_; + + virtual void Retrieve(const DicomMap &findAnswer) = 0; + + explicit DicomRetrieveScuBaseJob(ServerContext &context); + + DicomRetrieveScuBaseJob(ServerContext &context, + const Json::Value &serialized); + + public: + virtual void AddFindAnswer(const DicomMap &answer); + + void AddQuery(const DicomMap& query); + + void AddFindAnswer(QueryRetrieveHandler &query, + size_t i); + + const DicomAssociationParameters &GetParameters() const + { + return parameters_; + } + + void SetLocalAet(const std::string &aet); + + void SetRemoteModality(const RemoteModalityParameters &remote); + + void SetTimeout(uint32_t timeout); + + void SetQueryFormat(DicomToJsonFormat format); + + DicomToJsonFormat GetQueryFormat() const + { + return queryFormat_; + } + + virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; + + virtual void GetPublicContent(Json::Value &value) const ORTHANC_OVERRIDE; + + virtual bool Serialize(Json::Value &target) const ORTHANC_OVERRIDE; + + virtual void OnProgressUpdated(uint16_t nbRemainingSubOperations, + uint16_t nbCompletedSubOperations, + uint16_t nbFailedSubOperations, + uint16_t nbWarningSubOperations) ORTHANC_OVERRIDE; + + virtual float GetProgress() const ORTHANC_OVERRIDE; + + virtual bool NeedsProgressUpdateBetweenSteps() const ORTHANC_OVERRIDE + { + return true; + } + + }; +}
--- a/OrthancServer/Sources/ServerJobs/IStorageCommitmentFactory.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/IStorageCommitmentFactory.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/LuaJobManager.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/LuaJobManager.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/LuaJobManager.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/LuaJobManager.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/MergeStudyJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -49,7 +49,7 @@ // Add all the instances of the series as to be processed std::list<std::string> instances; - GetContext().GetIndex().GetChildren(instances, series); + GetContext().GetIndex().GetChildren(instances, ResourceType_Series, series); for (std::list<std::string>::const_iterator it = instances.begin(); it != instances.end(); ++it) @@ -69,7 +69,7 @@ else { std::list<std::string> series; - GetContext().GetIndex().GetChildren(series, study); + GetContext().GetIndex().GetChildren(series, ResourceType_Study, study); for (std::list<std::string>::const_iterator it = series.begin(); it != series.end(); ++it) @@ -190,7 +190,7 @@ DicomTag::AddTagsForModule(removals_, DicomModule_Study); std::list<std::string> instances; - GetContext().GetIndex().GetChildInstances(instances, targetStudy); + GetContext().GetIndex().GetChildInstances(instances, targetStudy, ResourceType_Study); if (instances.empty()) { @@ -353,7 +353,7 @@ } - void MergeStudyJob::GetPublicContent(Json::Value& value) + void MergeStudyJob::GetPublicContent(Json::Value& value) const { CleaningInstancesJob::GetPublicContent(value); value["TargetStudy"] = targetStudy_; @@ -386,7 +386,7 @@ } - bool MergeStudyJob::Serialize(Json::Value& target) + bool MergeStudyJob::Serialize(Json::Value& target) const { if (!CleaningInstancesJob::Serialize(target)) {
--- a/OrthancServer/Sources/ServerJobs/MergeStudyJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/MergeStudyJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -89,13 +89,13 @@ { } - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = "MergeStudy"; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; }; }
--- a/OrthancServer/Sources/ServerJobs/Operations/DeleteResourceOperation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/DeleteResourceOperation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/DeleteResourceOperation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/DeleteResourceOperation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/DicomInstanceOperationValue.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/DicomInstanceOperationValue.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/DicomInstanceOperationValue.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/DicomInstanceOperationValue.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/ModifyInstanceOperation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/ModifyInstanceOperation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/ModifyInstanceOperation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/ModifyInstanceOperation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/StorePeerOperation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/StorePeerOperation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/StorePeerOperation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/StorePeerOperation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/StoreScuOperation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/StoreScuOperation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/StoreScuOperation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/StoreScuOperation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/SystemCallOperation.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/SystemCallOperation.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/Operations/SystemCallOperation.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/Operations/SystemCallOperation.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/OrthancJobUnserializer.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/OrthancJobUnserializer.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/OrthancJobUnserializer.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/OrthancJobUnserializer.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerJobs/OrthancPeerStoreJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/OrthancPeerStoreJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -220,7 +220,7 @@ } - void OrthancPeerStoreJob::GetPublicContent(Json::Value& value) + void OrthancPeerStoreJob::GetPublicContent(Json::Value& value) const { SetOfInstancesJob::GetPublicContent(value); @@ -285,7 +285,7 @@ } - bool OrthancPeerStoreJob::Serialize(Json::Value& target) + bool OrthancPeerStoreJob::Serialize(Json::Value& target) const { if (!SetOfInstancesJob::Serialize(target)) {
--- a/OrthancServer/Sources/ServerJobs/OrthancPeerStoreJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/OrthancPeerStoreJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -92,13 +92,13 @@ virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; // For pausing jobs - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = "OrthancPeerStore"; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; }; }
--- a/OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -542,7 +542,7 @@ } - void ResourceModificationJob::GetPublicContent(Json::Value& value) + void ResourceModificationJob::GetPublicContent(Json::Value& value) const { boost::recursive_mutex::scoped_lock lock(outputMutex_); @@ -636,7 +636,7 @@ } } - bool ResourceModificationJob::Serialize(Json::Value& value) + bool ResourceModificationJob::Serialize(Json::Value& value) const { if (modification_.get() == NULL) {
--- a/OrthancServer/Sources/ServerJobs/ResourceModificationJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/ResourceModificationJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -116,14 +116,14 @@ // Only possible if "IsSingleResourceModification()" ResourceType GetOutputLevel() const; - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = "ResourceModification"; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& value) const ORTHANC_OVERRIDE; virtual void Reset() ORTHANC_OVERRIDE;
--- a/OrthancServer/Sources/ServerJobs/SplitStudyJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/SplitStudyJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -213,7 +213,7 @@ // Add all the instances of the series as to be processed std::list<std::string> instances; - GetContext().GetIndex().GetChildren(instances, series); + GetContext().GetIndex().GetChildren(instances, ResourceType_Series, series); for (std::list<std::string>::const_iterator it = instances.begin(); it != instances.end(); ++it) @@ -306,7 +306,7 @@ } - void SplitStudyJob::GetPublicContent(Json::Value& value) + void SplitStudyJob::GetPublicContent(Json::Value& value) const { CleaningInstancesJob::GetPublicContent(value); @@ -351,7 +351,7 @@ } - bool SplitStudyJob::Serialize(Json::Value& target) + bool SplitStudyJob::Serialize(Json::Value& target) const { if (!CleaningInstancesJob::Serialize(target)) {
--- a/OrthancServer/Sources/ServerJobs/SplitStudyJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/SplitStudyJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -113,13 +113,13 @@ { } - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = "SplitStudy"; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; }; }
--- a/OrthancServer/Sources/ServerJobs/StorageCommitmentScpJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/StorageCommitmentScpJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -404,7 +404,7 @@ } - void StorageCommitmentScpJob::GetPublicContent(Json::Value& value) + void StorageCommitmentScpJob::GetPublicContent(Json::Value& value) const { SetOfCommandsJob::GetPublicContent(value); @@ -434,7 +434,7 @@ } - bool StorageCommitmentScpJob::Serialize(Json::Value& target) + bool StorageCommitmentScpJob::Serialize(Json::Value& target) const { if (!SetOfCommandsJob::Serialize(target)) {
--- a/OrthancServer/Sources/ServerJobs/StorageCommitmentScpJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/StorageCommitmentScpJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -89,13 +89,13 @@ { } - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& target) const ORTHANC_OVERRIDE { target = "StorageCommitmentScp"; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; }; }
--- a/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -376,7 +376,7 @@ static const char* KEY_WORKERS_COUNT = "WorkersCount"; - void ThreadedSetOfInstancesJob::GetPublicContent(Json::Value& target) + void ThreadedSetOfInstancesJob::GetPublicContent(Json::Value& target) const { boost::recursive_mutex::scoped_lock lock(mutex_); @@ -391,7 +391,7 @@ } - bool ThreadedSetOfInstancesJob::Serialize(Json::Value& target) + bool ThreadedSetOfInstancesJob::Serialize(Json::Value& target) const { boost::recursive_mutex::scoped_lock lock(mutex_); @@ -478,7 +478,7 @@ return keepSource_; } - float ThreadedSetOfInstancesJob::GetProgress() + float ThreadedSetOfInstancesJob::GetProgress() const { boost::recursive_mutex::scoped_lock lock(mutex_);
--- a/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerJobs/ThreadedSetOfInstancesJob.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -140,15 +140,15 @@ virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; - virtual float GetProgress() ORTHANC_OVERRIDE; + virtual float GetProgress() const ORTHANC_OVERRIDE; bool IsStarted() const; virtual JobStepResult Step(const std::string& jobId) ORTHANC_OVERRIDE; - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE; - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; + virtual bool Serialize(Json::Value& target) const ORTHANC_OVERRIDE; virtual bool GetOutput(std::string& output, MimeType& mime,
--- a/OrthancServer/Sources/ServerToolbox.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerToolbox.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/ServerToolbox.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/ServerToolbox.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/SimpleInstanceOrdering.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,159 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeadersServer.h" +#include "SimpleInstanceOrdering.h" + +#include "../../OrthancFramework/Sources/Logging.h" +#include "../../OrthancFramework/Sources/Toolbox.h" +#include "../../OrthancFramework/Sources/SerializationToolbox.h" +#include "ServerEnumerations.h" +#include "ServerIndex.h" +#include "ResourceFinder.h" + +#include <algorithm> +#include <boost/lexical_cast.hpp> +#include <boost/noncopyable.hpp> + + +namespace Orthanc +{ + struct SimpleInstanceOrdering::Instance : public boost::noncopyable + { + private: + std::string instanceId_; + uint32_t indexInSeries_; + FileInfo fileInfo_; + + + public: + Instance(const std::string& instanceId, + uint32_t indexInSeries, + const FileInfo& fileInfo) : + instanceId_(instanceId), + indexInSeries_(indexInSeries), + fileInfo_(fileInfo) + { + } + + const std::string& GetIdentifier() const + { + return instanceId_; + } + + uint32_t GetIndexInSeries() const + { + return indexInSeries_; + } + + const FileInfo& GetFileInfo() const + { + return fileInfo_; + } + }; + + bool SimpleInstanceOrdering::IndexInSeriesComparator(const SimpleInstanceOrdering::Instance* a, + const SimpleInstanceOrdering::Instance* b) + { + return a->GetIndexInSeries() < b->GetIndexInSeries(); + } + + + SimpleInstanceOrdering::SimpleInstanceOrdering(ServerIndex& index, + const std::string& seriesId) : + hasDuplicateIndexInSeries_(false) + { + FindRequest request(ResourceType_Instance); + request.SetOrthancSeriesId(seriesId); + request.SetRetrieveMetadata(true); + request.SetRetrieveAttachments(true); + + FindResponse response; + index.ExecuteFind(response, request); + + std::set<uint32_t> allIndexInSeries; + + for (size_t i = 0; i < response.GetSize(); ++i) + { + const FindResponse::Resource& resource = response.GetResourceByIndex(i); + std::string instanceId = resource.GetIdentifier(); + + std::string strIndexInSeries; + uint32_t indexInSeries = 0; + FileInfo fileInfo; + int64_t revisionNotUsed; + + if (resource.LookupMetadata(strIndexInSeries, ResourceType_Instance, MetadataType_Instance_IndexInSeries)) + { + SerializationToolbox::ParseUnsignedInteger32(indexInSeries, strIndexInSeries); + } + + if (resource.LookupAttachment(fileInfo, revisionNotUsed, FileContentType_Dicom)) + { + allIndexInSeries.insert(indexInSeries); + instances_.push_back(new SimpleInstanceOrdering::Instance(instanceId, indexInSeries, fileInfo)); + } + } + + // if there are duplicates, the set will be smaller than the vector + hasDuplicateIndexInSeries_ = allIndexInSeries.size() != instances_.size(); + + std::sort(instances_.begin(), instances_.end(), IndexInSeriesComparator); + } + + SimpleInstanceOrdering::~SimpleInstanceOrdering() + { + for (std::vector<Instance*>::iterator + it = instances_.begin(); it != instances_.end(); ++it) + { + if (*it != NULL) + { + delete *it; + } + } + } + + const std::string& SimpleInstanceOrdering::GetInstanceId(size_t index) const + { + return instances_[index]->GetIdentifier(); + } + + uint32_t SimpleInstanceOrdering::GetInstanceIndexInSeries(size_t index) const + { + if (hasDuplicateIndexInSeries_) + { + // if there are duplicates, we count the instances from 0 + return index; + } + else + { + // if there are no duplicates, we return the real index in series (that may not start at 0 but that is more human friendly) + return instances_[index]->GetIndexInSeries(); + } + } + + const FileInfo& SimpleInstanceOrdering::GetInstanceFileInfo(size_t index) const + { + return instances_[index]->GetFileInfo(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/SimpleInstanceOrdering.h Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,61 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../../OrthancFramework/Sources/DicomFormat/DicomMap.h" +#include "../../OrthancFramework/Sources/FileStorage/FileInfo.h" + +namespace Orthanc +{ + class ServerIndex; + + class SimpleInstanceOrdering + { + private: + struct Instance; + + std::vector<Instance*> instances_; + bool hasDuplicateIndexInSeries_; + + public: + SimpleInstanceOrdering(ServerIndex& index, + const std::string& seriesId); + ~SimpleInstanceOrdering(); + + size_t GetInstancesCount() const + { + return instances_.size(); + } + + const std::string& GetInstanceId(size_t index) const; + + uint32_t GetInstanceIndexInSeries(size_t index) const; + + const FileInfo& GetInstanceFileInfo(size_t index) const; + + private: + static bool IndexInSeriesComparator(const SimpleInstanceOrdering::Instance* a, + const SimpleInstanceOrdering::Instance* b); + }; +}
--- a/OrthancServer/Sources/SliceOrdering.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/SliceOrdering.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -198,8 +198,7 @@ try { - int64_t revision; // Ignored - if (index.LookupMetadata(s, revision, instanceId, ResourceType_Instance, MetadataType_Instance_IndexInSeries)) + if (index.LookupMetadata(s, instanceId, ResourceType_Instance, MetadataType_Instance_IndexInSeries)) { indexInSeries_ = boost::lexical_cast<size_t>(Toolbox::StripSpaces(s)); hasIndexInSeries_ = true; @@ -297,7 +296,7 @@ void SliceOrdering::CreateInstances() { std::list<std::string> instancesId; - index_.GetChildren(instancesId, seriesId_); + index_.GetChildren(instancesId, ResourceType_Series, seriesId_); instances_.reserve(instancesId.size()); for (std::list<std::string>::const_iterator
--- a/OrthancServer/Sources/SliceOrdering.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/SliceOrdering.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/StorageCommitmentReports.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/StorageCommitmentReports.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/StorageCommitmentReports.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/StorageCommitmentReports.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/Sources/main.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/Sources/main.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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,6 +63,8 @@ static const char* const KEY_DICOM_TLS_MINIMUM_PROTOCOL_VERSION = "DicomTlsMinimumProtocolVersion"; static const char* const KEY_DICOM_TLS_ACCEPTED_CIPHERS = "DicomTlsCiphersAccepted"; static const char* const KEY_MAXIMUM_PDU_LENGTH = "MaximumPduLength"; +static const char* const KEY_READ_ONLY = "ReadOnly"; +static const char* const KEY_MAXIMUM_CONCURRENT_DCMTK_TRANSCODERS = "MaximumConcurrentDcmtkTranscoders"; class OrthancStoreRequestHandler : public IStoreRequestHandler @@ -494,6 +496,13 @@ context_.GetAcceptedTransferSyntaxes(target); } + virtual void GetProposedStorageTransferSyntaxes(std::list<DicomTransferSyntax>& target, + const std::string& remoteIp, + const std::string& remoteAet, + const std::string& calledAet) ORTHANC_OVERRIDE + { + context_.GetProposedStorageTransferSyntaxes(target); + } virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, const std::string& remoteAet, @@ -501,6 +510,12 @@ { return context_.IsUnknownSopClassAccepted(); } + + virtual void GetAcceptedSopClasses(std::set<std::string>& sopClasses, + size_t maxCount) ORTHANC_OVERRIDE + { + context_.GetAcceptedSopClasses(sopClasses, maxCount); + } }; @@ -746,8 +761,8 @@ << path << " " << ORTHANC_VERSION << std::endl << "Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics Department, University Hospital of Liege (Belgium)" << std::endl << "Copyright (C) 2017-2023 Osimis S.A. (Belgium)" << std::endl - << "Copyright (C) 2024-2024 Orthanc Team SRL (Belgium)" << std::endl - << "Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain (Belgium)" << std::endl + << "Copyright (C) 2024-2025 Orthanc Team SRL (Belgium)" << std::endl + << "Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain (Belgium)" << std::endl << "Licensing GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>." << std::endl << "This is free software: you are free to change and redistribute it." << std::endl << "There is NO WARRANTY, to the extent permitted by law." << std::endl @@ -887,6 +902,7 @@ PrintErrorCode(ErrorCode_AlreadyExistingTag, "Cannot override the value of a tag that already exists"); PrintErrorCode(ErrorCode_NoStorageCommitmentHandler, "No request handler factory for DICOM N-ACTION SCP (storage commitment)"); PrintErrorCode(ErrorCode_NoCGetHandler, "No request handler factory for DICOM C-GET SCP"); + PrintErrorCode(ErrorCode_DicomGetUnavailable, "DicomUserConnection: The C-GET command is not supported by the remote SCP"); PrintErrorCode(ErrorCode_UnsupportedMediaType, "Unsupported media type"); } @@ -1519,16 +1535,23 @@ { size_t maxCompletedJobs; bool readOnly; - + unsigned int maxDcmtkConcurrentTranscoders; + { OrthancConfiguration::ReaderLock lock; // These configuration options must be set before creating the // ServerContext, otherwise the possible Lua scripts will not be // able to properly issue HTTP/HTTPS queries + + std::string httpsCaCertificates = lock.GetConfiguration().GetStringParameter("HttpsCACertificates", ""); + if (!httpsCaCertificates.empty()) + { + httpsCaCertificates = lock.GetConfiguration().InterpretStringParameterAsPath(httpsCaCertificates); + } + HttpClient::ConfigureSsl(lock.GetConfiguration().GetBooleanParameter("HttpsVerifyPeers", true), - lock.GetConfiguration().InterpretStringParameterAsPath - (lock.GetConfiguration().GetStringParameter("HttpsCACertificates", ""))); + httpsCaCertificates); HttpClient::SetDefaultVerbose(lock.GetConfiguration().GetBooleanParameter("HttpVerbose", false)); // The value "0" below makes the class HttpClient use its default @@ -1547,8 +1570,15 @@ } // New option in Orthanc 1.12.5 - readOnly = lock.GetConfiguration().GetBooleanParameter("ReadOnly", false); + readOnly = lock.GetConfiguration().GetBooleanParameter(KEY_READ_ONLY, false); + // New option in Orthanc 1.12.6 + maxDcmtkConcurrentTranscoders = lock.GetConfiguration().GetUnsignedIntegerParameter(KEY_MAXIMUM_CONCURRENT_DCMTK_TRANSCODERS, 0); + if (maxDcmtkConcurrentTranscoders == 0) + { + maxDcmtkConcurrentTranscoders = static_cast<unsigned int>(boost::thread::hardware_concurrency()); + } + // Configuration of DICOM TLS for Orthanc SCU (since Orthanc 1.9.0) DicomAssociationParameters::SetDefaultOwnCertificatePath( lock.GetConfiguration().GetStringParameter(KEY_DICOM_TLS_PRIVATE_KEY, ""), @@ -1563,7 +1593,7 @@ lock.GetConfiguration().GetBooleanParameter(KEY_DICOM_TLS_REMOTE_CERTIFICATE_REQUIRED, true)); } - ServerContext context(database, storageArea, false /* not running unit tests */, maxCompletedJobs, readOnly); + ServerContext context(database, storageArea, false /* not running unit tests */, maxCompletedJobs, readOnly, maxDcmtkConcurrentTranscoders); { OrthancConfiguration::ReaderLock lock; @@ -1968,7 +1998,7 @@ SQLiteDatabaseWrapper inMemoryDatabase; inMemoryDatabase.Open(); MemoryStorageArea inMemoryStorage; - ServerContext context(inMemoryDatabase, inMemoryStorage, true /* unit testing */, 0 /* max completed jobs */, false /* readonly */); + ServerContext context(inMemoryDatabase, inMemoryStorage, true /* unit testing */, 0 /* max completed jobs */, false /* readonly */, 1 /* DCMTK concurrent transcoders */); OrthancRestApi restApi(context, false /* no Orthanc Explorer */); restApi.GenerateOpenApiDocumentation(openapi); context.Stop(); @@ -2019,7 +2049,7 @@ SQLiteDatabaseWrapper inMemoryDatabase; inMemoryDatabase.Open(); MemoryStorageArea inMemoryStorage; - ServerContext context(inMemoryDatabase, inMemoryStorage, true /* unit testing */, 0 /* max completed jobs */, false /* readonly */); + ServerContext context(inMemoryDatabase, inMemoryStorage, true /* unit testing */, 0 /* max completed jobs */, false /* readonly */, 1 /* DCMTK concurrent transcoders */); OrthancRestApi restApi(context, false /* no Orthanc Explorer */); restApi.GenerateReStructuredTextCheatSheet(cheatsheet, "https://orthanc.uclouvain.be/api/index.html"); context.Stop();
--- a/OrthancServer/UnitTestsSources/DatabaseLookupTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/DatabaseLookupTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/UnitTestsSources/LuaServerTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/LuaServerTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -138,38 +138,43 @@ TEST(Lua, Http) { Orthanc::LuaContext lua; - -#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 - // The "http://www.orthanc-server.com/downloads/third-party/" does - // not automatically redirect to HTTPS, so we use it even if the - // OpenSSL/HTTPS support is disabled in curl - const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/"; - -#if LUA_VERSION_NUM >= 502 - // Since Lua >= 5.2.0, the function "loadstring" has been replaced by "load" - lua.Execute("JSON = load(HttpGet('" + BASE + "JSON.lua')) ()"); -#else - lua.Execute("JSON = loadstring(HttpGet('" + BASE + "JSON.lua')) ()"); -#endif - - const std::string url(BASE + "Product.json"); -#endif + ASSERT_TRUE(lua.IsHttpsVerifyPeers()); + lua.SetHttpsVerifyPeers(false); + ASSERT_FALSE(lua.IsHttpsVerifyPeers()); std::string s; lua.Execute(s, "print(HttpGet({}))"); ASSERT_EQ("nil", Orthanc::Toolbox::StripSpaces(s)); -#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 - lua.Execute(s, "print(string.len(HttpGet(\"" + url + "\")))"); - ASSERT_LE(100, boost::lexical_cast<int>(Orthanc::Toolbox::StripSpaces(s))); +#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 + // The "http://httpbin.org/get" URL does not automatically redirect + // to HTTPS, so we can use it even if the OpenSSL/HTTPS support is + // disabled in curl - // Parse a JSON file - lua.Execute(s, "print(JSON:decode(HttpGet(\"" + url + "\")) ['Product'])"); - ASSERT_EQ("OrthancClient", Orthanc::Toolbox::StripSpaces(s)); + const std::string URL = "http://httpbin.org/get"; + lua.Execute(s, "print(HttpGet(\"" + URL + "\"))"); + + Json::Value json; + Orthanc::Toolbox::ReadJson(json, s); + + ASSERT_TRUE(json.type() == Json::objectValue); + ASSERT_TRUE(json.isMember("url")); + ASSERT_EQ(URL, json["url"].asString()); #if 0 // This part of the test can only be executed if one instance of - // Orthanc is running on the localhost + // Orthanc is running on the localhost, with configuration option + // "ExecuteLuaEnabled" equals to "true" + + const std::string JSON_LUA_TOOLBOX = "https://regex.info/code/JSON.lua"; + lua.Execute("HttpGet('" + JSON_LUA_TOOLBOX + "')"); + +#if LUA_VERSION_NUM >= 502 + // Since Lua >= 5.2.0, the function "loadstring" has been replaced by "load" + lua.Execute("JSON = load(HttpGet('" + JSON_LUA_TOOLBOX + "')) ()"); +#else + lua.Execute("JSON = loadstring(HttpGet('" + JSON_LUA_TOOLBOX + "')) ()"); +#endif lua.Execute("modality = {}"); lua.Execute("table.insert(modality, 'ORTHANC')");
--- a/OrthancServer/UnitTestsSources/PluginsTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/PluginsTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/UnitTestsSources/PrecompiledHeadersUnitTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/PrecompiledHeadersUnitTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/UnitTestsSources/PrecompiledHeadersUnitTests.h Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/PrecompiledHeadersUnitTests.h Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/UnitTestsSources/ServerConfigTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -0,0 +1,176 @@ +/** + * 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-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "PrecompiledHeadersUnitTests.h" +#include <gtest/gtest.h> + +#include "../../OrthancFramework/Sources/Compatibility.h" +#include "../../OrthancFramework/Sources/FileStorage/MemoryStorageArea.h" +#include "../../OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h" +#include "../../OrthancFramework/Sources/Logging.h" +#include "../../OrthancFramework/Sources/SerializationToolbox.h" + +#include "../Sources/Database/SQLiteDatabaseWrapper.h" +#include "../Sources/ServerContext.h" + +using namespace Orthanc; + +TEST(ServerConfig, AcceptedSopClasses) +{ + const std::string path = "UnitTestsStorage"; + + MemoryStorageArea storage; + SQLiteDatabaseWrapper db; // The SQLite DB is in memory + db.Open(); + ServerContext context(db, storage, true /* running unit tests */, 10, false, 1); + + { // default config -> all SOP Classes should be accepted + std::set<std::string> s; + + context.GetAcceptedSopClasses(s, 0); + ASSERT_LE(100u, s.size()); + + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.4") != s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.1.1") != s.end()); + + context.GetAcceptedSopClasses(s, 1); + ASSERT_EQ(1u, s.size()); + } + + { + std::list<std::string> acceptedStorageClasses; + std::set<std::string> rejectedStorageClasses; + + std::set<std::string> s; + context.GetAcceptedSopClasses(s, 0); + size_t allSize = s.size(); + + { // default config but reject one class + acceptedStorageClasses.clear(); + rejectedStorageClasses.clear(); + rejectedStorageClasses.insert("1.2.840.10008.5.1.4.1.1.4"); + + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_EQ(allSize - 1, s.size()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.4") == s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.1.1") != s.end()); + + context.GetAcceptedSopClasses(s, 1); + ASSERT_EQ(1u, s.size()); + } + + { // default config but reject one regex + acceptedStorageClasses.clear(); + rejectedStorageClasses.clear(); + rejectedStorageClasses.insert("1.2.840.10008.5.1.4.1.*"); + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.4") == s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.1.1") == s.end()); + } + + { // accept a single - no rejection + acceptedStorageClasses.clear(); + acceptedStorageClasses.push_back("1.2.840.10008.5.1.4.1.1.4"); + rejectedStorageClasses.clear(); + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_EQ(1, s.size()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.4") != s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.1.1") == s.end()); + } + + { // accept from regex - reject one + acceptedStorageClasses.clear(); + acceptedStorageClasses.push_back("1.2.840.10008.5.1.4.1.*"); + rejectedStorageClasses.clear(); + rejectedStorageClasses.insert("1.2.840.10008.5.1.4.1.1.12.1.1"); + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_LE(10, s.size()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.4") != s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.1.1") == s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.2.1") != s.end()); + } + + { // accept from regex - reject from regex + acceptedStorageClasses.clear(); + acceptedStorageClasses.push_back("1.2.840.10008.5.1.4.1.*"); + rejectedStorageClasses.clear(); + rejectedStorageClasses.insert("1.2.840.10008.5.1.4.1.1.12.1.*"); + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_LE(10, s.size()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.4") != s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.1.1") == s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.2.1") != s.end()); + } + + { // accept one that is unknown form DCMTK + acceptedStorageClasses.clear(); + acceptedStorageClasses.push_back("1.2.3.4"); + rejectedStorageClasses.clear(); + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_EQ(1, s.size()); + ASSERT_TRUE(s.find("1.2.3.4") != s.end()); + } + + { // accept the default ones + a custom one + acceptedStorageClasses.clear(); + acceptedStorageClasses.push_back("1.2.840.*"); + acceptedStorageClasses.push_back("1.2.3.4"); + rejectedStorageClasses.clear(); + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_LE(100u, s.size()); + ASSERT_TRUE(s.find("1.2.3.4") != s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.2.1") != s.end()); + } + + { // test the ? in regex to replace a single char + acceptedStorageClasses.clear(); + acceptedStorageClasses.push_back("1.2.840.10008.5.1.4.1.1.12.2.?"); + acceptedStorageClasses.push_back("1.2.3.4"); + rejectedStorageClasses.clear(); + context.SetAcceptedSopClasses(acceptedStorageClasses, rejectedStorageClasses); + + context.GetAcceptedSopClasses(s, 0); + ASSERT_EQ(2u, s.size()); + ASSERT_TRUE(s.find("1.2.3.4") != s.end()); + ASSERT_TRUE(s.find("1.2.840.10008.5.1.4.1.1.12.2.1") != s.end()); + } + + } + + context.Stop(); + db.Close(); +}
--- a/OrthancServer/UnitTestsSources/ServerIndexTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/ServerIndexTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -620,7 +620,7 @@ FilesystemStorage storage(path); SQLiteDatabaseWrapper db; // The SQLite DB is in memory db.Open(); - ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */); + ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */, 1 /* DCMTK concurrent transcoders */); context.SetupJobsEngine(true, false); ServerIndex& index = context.GetIndex(); @@ -702,7 +702,7 @@ FilesystemStorage storage(path); SQLiteDatabaseWrapper db; // The SQLite DB is in memory db.Open(); - ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */); + ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */, 1 /* DCMTK concurrent transcoders */); context.SetupJobsEngine(true, false); ServerIndex& index = context.GetIndex(); @@ -819,7 +819,7 @@ MemoryStorageArea storage; SQLiteDatabaseWrapper db; // The SQLite DB is in memory db.Open(); - ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */); + ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */, 1 /* DCMTK concurrent transcoders */); context.SetupJobsEngine(true, false); context.SetCompressionEnabled(true); @@ -864,15 +864,15 @@ { FileInfo nope; int64_t revision; - ASSERT_FALSE(context.GetIndex().LookupAttachment(nope, revision, id, FileContentType_DicomAsJson)); + ASSERT_FALSE(context.GetIndex().LookupAttachment(nope, revision, ResourceType_Instance, id, FileContentType_DicomAsJson)); } FileInfo dicom1, pixelData1; - int64_t revision; - ASSERT_TRUE(context.GetIndex().LookupAttachment(dicom1, revision, id, FileContentType_Dicom)); + int64_t revision = -1; + ASSERT_TRUE(context.GetIndex().LookupAttachment(dicom1, revision, ResourceType_Instance, id, FileContentType_Dicom)); ASSERT_EQ(0, revision); revision = -1; - ASSERT_TRUE(context.GetIndex().LookupAttachment(pixelData1, revision, id, FileContentType_DicomUntilPixelData)); + ASSERT_TRUE(context.GetIndex().LookupAttachment(pixelData1, revision, ResourceType_Instance, id, FileContentType_DicomUntilPixelData)); ASSERT_EQ(0, revision); context.GetIndex().GetGlobalStatistics(diskSize, uncompressedSize, countPatients, @@ -914,14 +914,14 @@ { FileInfo nope; int64_t revision; - ASSERT_FALSE(context.GetIndex().LookupAttachment(nope, revision, id, FileContentType_DicomAsJson)); + ASSERT_FALSE(context.GetIndex().LookupAttachment(nope, revision, ResourceType_Instance, id, FileContentType_DicomAsJson)); } FileInfo dicom2, pixelData2; - ASSERT_TRUE(context.GetIndex().LookupAttachment(dicom2, revision, id, FileContentType_Dicom)); + ASSERT_TRUE(context.GetIndex().LookupAttachment(dicom2, revision, ResourceType_Instance, id, FileContentType_Dicom)); ASSERT_EQ(0, revision); revision = -1; - ASSERT_TRUE(context.GetIndex().LookupAttachment(pixelData2, revision, id, FileContentType_DicomUntilPixelData)); + ASSERT_TRUE(context.GetIndex().LookupAttachment(pixelData2, revision, ResourceType_Instance, id, FileContentType_DicomUntilPixelData)); ASSERT_EQ(0, revision); context.GetIndex().GetGlobalStatistics(diskSize, uncompressedSize, countPatients, @@ -984,7 +984,7 @@ MemoryStorageArea storage; SQLiteDatabaseWrapper db; // The SQLite DB is in memory db.Open(); - ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */); + ServerContext context(db, storage, true /* running unit tests */, 10, false /* readonly */, 1 /* DCMTK concurrent transcoders */); context.SetupJobsEngine(true, false); context.SetCompressionEnabled(compression);
--- a/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -106,24 +106,24 @@ { } - virtual float GetProgress() ORTHANC_OVERRIDE + virtual float GetProgress() const ORTHANC_OVERRIDE { return static_cast<float>(count_) / static_cast<float>(steps_ - 1); } - virtual void GetJobType(std::string& type) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& type) const ORTHANC_OVERRIDE { type = "DummyJob"; } - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE + virtual bool Serialize(Json::Value& value) const ORTHANC_OVERRIDE { value = Json::objectValue; value["Type"] = "DummyJob"; return true; } - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE + virtual void GetPublicContent(Json::Value& value) const ORTHANC_OVERRIDE { value["hello"] = "world"; } @@ -202,7 +202,7 @@ { } - virtual void GetJobType(std::string& s) ORTHANC_OVERRIDE + virtual void GetJobType(std::string& s) const ORTHANC_OVERRIDE { s = "DummyInstancesJob"; } @@ -536,7 +536,7 @@ OrthancJobsSerialization() { db_.Open(); - context_.reset(new ServerContext(db_, storage_, true /* running unit tests */, 10, false /* readonly */)); + context_.reset(new ServerContext(db_, storage_, true /* running unit tests */, 10, false /* readonly */, 1 /* DCMTK concurrent transcoders */)); context_->SetupJobsEngine(true, false); }
--- a/OrthancServer/UnitTestsSources/SizeOfTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/SizeOfTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/UnitTestsSources/UnitTestsMain.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/UnitTestsMain.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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
--- a/OrthancServer/UnitTestsSources/VersionsTests.cpp Wed Oct 09 11:06:20 2024 +0200 +++ b/OrthancServer/UnitTestsSources/VersionsTests.cpp Thu Jan 30 17:41:33 2025 +0100 @@ -3,8 +3,8 @@ * 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 + * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2025 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 @@ -113,7 +113,7 @@ TEST(Versions, BoostStatic) { - ASSERT_TRUE(std::string(BOOST_LIB_VERSION) == "1_85" || + ASSERT_TRUE(std::string(BOOST_LIB_VERSION) == "1_86" || std::string(BOOST_LIB_VERSION) == "1_69" /* if USE_LEGACY_BOOST */); }
--- a/README Wed Oct 09 11:06:20 2024 +0200 +++ b/README Thu Jan 30 17:41:33 2025 +0100 @@ -49,9 +49,7 @@ Licensing --------- -Orthanc is licensed under the GPLv3 license, with the OpenSSL -exception: -http://people.gnome.org/~markmc/openssl-and-the-gpl.html +Orthanc is licensed under the GPLv3 license. Full information about the licensing of the Orthanc ecosystem is available in the Orthanc Book:
--- a/TODO Wed Oct 09 11:06:20 2024 +0200 +++ b/TODO Thu Jan 30 17:41:33 2025 +0100 @@ -65,6 +65,11 @@ * Add configurations to enable/disable warnings: - Modifying an instance while keeping its original SOPInstanceUID: This should be avoided! - Modifying a study while keeping its original StudyInstanceUID: This should be avoided! + In order to be able to disable/enable warnings in both the server and the framework, we should add a map of + enabled warnings in the logging classes directly and have something like: + LOG_WARNING_IF_ENABLED("Warning_ID") << ... + ENABLE_WARNING("Warning_ID", true) + Warnings from Framework should have a separate range like W999_ or WF001_ ... * Store the job registry in a dedicatd table in DB ? https://discourse.orthanc-server.org/t/performance-issue-when-adding-a-lot-of-jobs-in-the-queue/3915/2 Note: that might also be the right time to have a central jobs registry when working @@ -206,7 +211,12 @@ Mid-term -------- -* Support C-GET SCU (note that C-GET SCP was introduced in Orthanc 1.7.0) +* Check how Orthanc shall behave wrt to AcceptedSopClasses in these situations (consider Orthanc + accepts CT but not PT) + - What shall we log/warn if an external modality tries to send a PT/CT + - What shall we log/warn if we try to C-GET a PT/CT + Should the rejected files be logged as Failed, Warning, Refused, ... + Note: some tentative work has been initiated in the get-scu-test branch. * Support "Retrieve AE Title" (0008,0054) in C-FIND: - On SCP side: done by https://orthanc.uclouvain.be/hg/orthanc/rev/1ec3e1e18f50 - On SCU side: @@ -216,9 +226,6 @@ * Strict hierarchical C-FIND: https://groups.google.com/d/msg/orthanc-users/VBHpeGVSNKM/tkaVvjWFBwAJ * report DIMSE error codes in Rest API and job status for /store /query /move /retrieve -* report progress report of C-Move operation in jop progress. There are - progress callbacks available in DIMSE_moveUser - https://groups.google.com/g/orthanc-users/c/c8cGnA7FzsE/m/BSs66D8wBwAJ * Log outgoing C-Find queries * Support other Transfer Syntaxes in the Worklist plugin: https://discourse.orthanc-server.org/t/could-you-please-create-an-option-to-set-the-transfer-syntax-in-the-worklist-plugin-currently-little-endian-explicit-is-fixed/4871 @@ -257,12 +264,6 @@ * (2) DicomMap: create a cache to the main DICOM tags index * (3) Check out rapidjson: https://github.com/miloyip/nativejson-benchmark -* For C-Find results: we could store the computed tags - in metadata on some events like NewSeries + DeletedSeries (same for other computer tags). - OtherTags that could be saved in Metadata as well: - - ModalitiesInStudy - - all computed counters at series/study/patient level - - RequestAttributesSequence (sequence that must be included in all DicomWeb QIDO-RS for series) * Long-shot & not sure it is even feasible at all: try to reduce memory usage by implementing streaming when receiving DICOM instances from the Rest API or from DICOM and store files directly to disk as they @@ -279,6 +280,9 @@ to Orthanc and/or the Storage plugin (instead of passing a memory buffer) -> the object-storage plugin could "stream" the file to the storage. The HTTP server could also "stream" its response from file handles. Transcoding should be "file based" too. + Alternative option 4: Catch out-of-memory exceptions at quite high level in HTTPHandlers and DICOM receivers + and implement retries. After a few retries, fail for good and return "out-of-resources". + Would be interesting to log these errors and count them in the prometheus metrics. * To investigate: usage of mapped_file (not only in the indexer plugin): https://discourse.orthanc-server.org/t/patch-for-orthanc-indexer-plugin-crashing-on-big-non-dicom-files/3849/7 @@ -315,8 +319,22 @@ https://groups.google.com/g/orthanc-users/c/ymtaAmgSs6Q/m/PqVBactQAQAJ * Add an index on the UUID column in the DelayedDeletion plugin: https://discourse.orthanc-server.org/t/delayeddeletion-improvement-unique-index-on-pending-uuid-column/4032 +* Orthanc shall refuse to start if one registers 2 storage plugins. + Right now, this is not possible because OrthancPluginRegisterStorageArea2 does not return any value + and it can not throw an Exception because that's a core function called from a plugin -> the Exception + can not cross the C/C++ frontier safely -> we need a OrthancPluginRegisterStorageArea3 with a return value. + Ex: install DelayedDeletion + S3 storage. Right now, the second plugin to load is just ignored with an error + message in the logs. +----------- +Housekeeper +----------- + +* The Housekeeper should just refuse to start if you are using a lossy transfer syntax because that would generate + new orthanc ids as well and there is a risk of messing up things. tools/reconstruct shall return a 400 as well. + https://discourse.orthanc-server.org/t/crashes-on-housekeeper-transcode-storing-in-s3/5330/2 + ---------------- Ideas of plugins ----------------