changeset 5754:f75596b224e0 find-refactoring-clean

merged find-refactoring -> find-refactoring-clean (integration tests ok)
author Alain Mazy <am@orthanc.team>
date Wed, 04 Sep 2024 10:54:00 +0200
parents afd421225eb4 (diff) fc591f166d53 (current diff)
children 58c549b881ae
files OrthancServer/Resources/Graveyard/FindRefactoringForSQLite.cpp OrthancServer/Sources/Database/FindResponse.cpp OrthancServer/Sources/ServerContext.cpp OrthancServer/Sources/ServerContext.h
diffstat 33 files changed, 94 insertions(+), 7949 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Resources/Graveyard/EclipseCodingStyle.xml	Wed Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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/OrthancServer/Resources/Graveyard/DatabaseOptimizations/LookupIdentifierQuery.cpp	Wed Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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 Sep 04 10:32:55 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/Sources/Database/StatelessDatabaseOperations.cpp	Wed Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Wed Sep 04 10:54:00 2024 +0200
@@ -573,285 +573,6 @@
   }
   
 
-  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>
-    {
-    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
-      {
-        // 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::GetDefaultMainDicomTagsSignature(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::GetDefaultMainDicomTagsSignature(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;
-        }
-      }
-    };
-
-    bool found;
-    Operations operations(db_.GetDatabaseCapabilities().HasLabelsSupport());
-    operations.Apply(*this, found, target, publicId, level, requestedTags, expandFlags);
-    return found;
-  }
-
-
   void StatelessDatabaseOperations::GetAllMetadata(std::map<MetadataType, std::string>& target,
                                                    const std::string& publicId,
                                                    ResourceType level)
@@ -1843,77 +1564,6 @@
   }
 
 
-  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 DatabaseConstraints&, ResourceType,
-                                                   const std::set<std::string>&, LabelsConstraint, size_t>
-    {
-    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())
-    {
-      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);
-    }
-
-    DatabaseConstraints 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());
-    }
-  }
-
-
   bool StatelessDatabaseOperations::DeleteResource(Json::Value& remainingAncestor,
                                                    const std::string& uuid,
                                                    ResourceType expectedType)
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Wed Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Wed Sep 04 10:54:00 2024 +0200
@@ -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:
@@ -625,12 +529,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);
@@ -727,14 +625,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);
--- a/OrthancServer/Sources/OrthancFindRequestHandler.cpp	Wed Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/OrthancFindRequestHandler.cpp	Wed Sep 04 10:54:00 2024 +0200
@@ -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, false /* don't expand */);
-      finder.SetDatabaseLookup(lookup);
-      finder.AddRequestedTags(requestedTags);
+    ResourceFinder finder(level, false /* don't expand */);
+    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/OrthancRestApi/OrthancRestResources.cpp	Wed Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Wed Sep 04 10:54:00 2024 +0200
@@ -146,77 +146,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)
   {
@@ -239,96 +168,45 @@
         .SetHttpGetSample("https://orthanc.uclouvain.be/demo/" + resources + "?since=0&limit=2", true);
       return;
     }
-    
-    ServerIndex& index = OrthancRestApi::GetIndex(call);
-    ServerContext& context = OrthancRestApi::GetContext(call);
-
-    if (true)
+
+    // 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);
+    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);
-      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);
   }
 
 
@@ -352,39 +230,19 @@
       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, true /* expand */);
+    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, true /* expand */);
-      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);
     }
   }
 
@@ -3173,70 +3031,6 @@
   }
 
 
-  namespace 
-  {
-    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_));
-      }
-    };
-  }
-
-
   static void Find(RestApiPostCall& call)
   {
     static const char* const KEY_CASE_SENSITIVE = "CaseSensitive";
@@ -3343,12 +3137,8 @@
       throw OrthancException(ErrorCode_BadRequest, 
                              "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be an array of strings");
     }
-    else if (true)
+    else
     {
-      /**
-       * EXPERIMENTAL VERSION
-       **/
-
       bool expand = false;
       if (request.isMember(KEY_EXPAND))
       {
@@ -3472,125 +3262,6 @@
       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)
-        {
-          throw OrthancException(ErrorCode_ParameterOutOfRange,
-                                 "Field \"" + std::string(KEY_LIMIT) + "\" must be a positive integer");
-        }
-
-        limit = static_cast<size_t>(tmp);
-      }
-
-      size_t since = 0;
-      if (request.isMember(KEY_SINCE))
-      {
-        int tmp = request[KEY_SINCE].asInt();
-        if (tmp < 0)
-        {
-          throw OrthancException(ErrorCode_ParameterOutOfRange,
-                                 "Field \"" + std::string(KEY_SINCE) + "\" must be a positive integer");
-        }
-
-        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)
-        {
-          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);
-        }
-      }
-
-      std::set<std::string> labels;
-
-      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)
-          {
-            throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS) + "\" must contain strings");
-          }
-          else
-          {
-            labels.insert(request[KEY_LABELS][i].asString());
-          }
-        }
-      }
-
-      LabelsConstraint labelsConstraint = LabelsConstraint_All;
-      
-      if (request.isMember(KEY_LABELS_CONSTRAINT))
-      {
-        const std::string& s = request[KEY_LABELS_CONSTRAINT].asString();
-        if (s == "All")
-        {
-          labelsConstraint = LabelsConstraint_All;
-        }
-        else if (s == "Any")
-        {
-          labelsConstraint = LabelsConstraint_Any;
-        }
-        else if (s == "None")
-        {
-          labelsConstraint = LabelsConstraint_None;
-        }
-        else
-        {
-          throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be \"All\", \"Any\", or \"None\"");
-        }
-      }
-      
-      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);
-    }
   }
 
 
@@ -3618,9 +3289,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));
@@ -3629,48 +3297,13 @@
     std::set<DicomTag> requestedTags;
     OrthancRestApi::GetRequestedTags(requestedTags, call);
 
-    if (true)
-    {
-      /**
-       * EXPERIMENTAL VERSION
-       **/
-
-      ResourceFinder finder(end, expand);
-      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);
+    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);
   }
 
 
@@ -3783,26 +3416,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);
     }
   }
 
@@ -4079,24 +3695,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";
@@ -4233,34 +3831,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);
           }
         }
       }
@@ -4275,38 +3849,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;
           }
         }
       }
--- a/OrthancServer/Sources/OrthancWebDav.cpp	Wed Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/OrthancWebDav.cpp	Wed Sep 04 10:54:00 2024 +0200
@@ -86,99 +86,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:
@@ -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:
@@ -1569,12 +1363,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 +1392,31 @@
         return false;
       }
 
-      if (true)
-      {
-        /**
-         * EXPERIMENTAL VERSION
-         **/
-
-        ResourceFinder finder(level, false /* don't expand */);
-        finder.SetDatabaseLookup(query);
-        finder.SetRetrieveMetadata(true);
+      ResourceFinder finder(level, false /* don't expand */);
+      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;
     }
@@ -1707,23 +1484,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 +1496,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 +1513,15 @@
       
         mime = MimeType_Dicom;
 
-        if (true)
-        {
-          /**
-           * EXPERIMENTAL VERSION
-           **/
-          ResourceFinder finder(ResourceType_Instance, false /* no expand */);
-          finder.SetDatabaseLookup(query);
-          finder.SetRetrieveMetadata(true);
-          finder.SetRetrieveAttachments(true);
+        ResourceFinder finder(ResourceType_Instance, false /* no expand */);
+        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
       {
--- a/OrthancServer/Sources/OrthancWebDav.h	Wed Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/OrthancWebDav.h	Wed Sep 04 10:54:00 2024 +0200
@@ -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/ServerContext.cpp	Wed Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/ServerContext.cpp	Wed Sep 04 10:54:00 2024 +0200
@@ -69,12 +69,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 ||
@@ -1542,188 +1536,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,
@@ -2131,600 +1943,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 Sep 04 10:32:55 2024 +0200
+++ b/OrthancServer/Sources/ServerContext.h	Wed Sep 04 10:54:00 2024 +0200
@@ -66,25 +66,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:
@@ -450,23 +431,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,
@@ -605,33 +569,6 @@
 
     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_;