changeset 5202:3a410992c626 db-protobuf

integration mainline->db-protobuf
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 29 Mar 2023 12:03:45 +0200
parents e9f3bddd30cc (diff) 345dac17a349 (current diff)
children 6b7f3ec30ac4
files
diffstat 14 files changed, 1370 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake	Wed Mar 29 12:03:45 2023 +0200
@@ -141,6 +141,11 @@
   unset(ENABLE_DCMTK_LOG CACHE)
 endif()
 
+if (NOT ENABLE_PROTOBUF)
+  unset(USE_SYSTEM_PROTOBUF CACHE)
+  add_definitions(-DORTHANC_ENABLE_PROTOBUF=0)
+endif()
+
 
 #####################################################################
 ## List of source files
@@ -476,6 +481,16 @@
 endif()
 
 
+##
+## Google Protocol Buffers
+##
+
+if (ENABLE_PROTOBUF)
+  include(${CMAKE_CURRENT_LIST_DIR}/ProtobufConfiguration.cmake)
+  add_definitions(-DORTHANC_ENABLE_PROTOBUF=1)
+endif()
+
+
 
 #####################################################################
 ## Inclusion of mandatory third-party dependencies
@@ -712,6 +727,7 @@
   ${LUA_SOURCES}
   ${MONGOOSE_SOURCES}
   ${OPENSSL_SOURCES}
+  ${PROTOBUF_LIBRARY_SOURCES}
   ${PUGIXML_SOURCES}
   ${SQLITE_SOURCES}
   ${UUID_SOURCES}
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake	Wed Mar 29 12:03:45 2023 +0200
@@ -70,6 +70,7 @@
 set(USE_SYSTEM_LUA ON CACHE BOOL "Use the system version of Lua")
 set(USE_SYSTEM_MONGOOSE ON CACHE BOOL "Use the system version of Mongoose")
 set(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL")
+set(USE_SYSTEM_PROTOBUF ON CACHE BOOL "Use the system version of Google Protocol Buffers")
 set(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml")
 set(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite")
 set(USE_SYSTEM_UUID ON CACHE BOOL "Use the system version of the uuid library from e2fsprogs")
@@ -123,6 +124,8 @@
 set(ENABLE_LOCALE OFF CACHE INTERNAL "Enable support for locales (notably in Boost)")
 set(ENABLE_LUA OFF CACHE INTERNAL "Enable support of Lua scripting")
 set(ENABLE_PNG OFF CACHE INTERNAL "Enable support of PNG")
+set(ENABLE_PROTOBUF OFF CACHE INTERNAL "Enable support for Google Protocol Buffers' library")
+set(ENABLE_PROTOBUF_COMPILER OFF CACHE INTERNAL "Enable support for Google Protocol Buffers' compiler")
 set(ENABLE_PUGIXML OFF CACHE INTERNAL "Enable support of XML through Pugixml")
 set(ENABLE_SQLITE OFF CACHE INTERNAL "Enable support of SQLite databases")
 set(ENABLE_ZLIB OFF CACHE INTERNAL "Enable support of zlib")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/CMake/ProtobufConfiguration.cmake	Wed Mar 29 12:03:45 2023 +0200
@@ -0,0 +1,85 @@
+# 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) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, 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/>.
+
+
+if (STATIC_BUILD OR NOT USE_SYSTEM_PROTOBUF)
+  if (ENABLE_PROTOBUF_COMPILER)
+    include(ExternalProject)
+    externalproject_add(ProtobufCompiler
+      SOURCE_DIR "${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/ProtocolBuffers"
+      BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/ProtobufCompiler-build"
+      # this helps triggering build when changing the external project
+      BUILD_ALWAYS 1
+      CMAKE_ARGS
+      -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+      -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
+      )
+
+    # The "protoc" compiler is built using "externalproject_add",
+    # which builds for the host platform, not for the target platform
+    if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+      set(Suffix ".exe")
+    else()
+      set(Suffix "")
+    endif()
+
+    set(PROTOC_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/protoc${Suffix})
+  endif()
+
+  include(${CMAKE_CURRENT_LIST_DIR}/../ProtocolBuffers/ProtobufLibrary.cmake)  
+  source_group(ThirdParty\\Protobuf REGULAR_EXPRESSION ${PROTOBUF_SOURCE_DIR}/.*)
+
+else()
+  if (CMAKE_CROSSCOMPILING)
+    message(FATAL_ERROR "If cross-compiling, the static version of Protocol Buffers should be used to avoid version mismatch")
+  endif()
+  
+  if (ENABLE_PROTOBUF_COMPILER)
+    find_program(PROTOC_EXECUTABLE protoc)
+    if (${PROTOC_EXECUTABLE} MATCHES "PROTOC_EXECUTABLE-NOTFOUND")
+      message(FATAL_ERROR "Please install the 'protoc' compiler for Protocol Buffers (package 'protobuf-compiler' on Debian/Ubuntu)")
+    endif()
+    add_custom_target(ProtobufCompiler)
+  endif()
+  
+  check_include_file_cxx(google/protobuf/any.h HAVE_PROTOBUF_H)
+  if (NOT HAVE_PROTOBUF_H)
+    message(FATAL_ERROR "Please install the libprotobuf-dev package")
+  endif()
+
+  set(CMAKE_REQUIRED_LIBRARIES "protobuf")
+
+  include(CheckCXXSourceCompiles) 
+  check_cxx_source_compiles(
+    "
+#include <google/protobuf/descriptor.h>
+int main()
+{
+  google::protobuf::FieldDescriptor::TypeName(google::protobuf::FieldDescriptor::TYPE_FLOAT);
+}
+"  HAVE_PROTOBUF_LIB)
+  if (NOT HAVE_PROTOBUF_LIB)
+    message(FATAL_ERROR "Cannot find the protobuf library")
+  endif()
+  
+  unset(CMAKE_REQUIRED_LIBRARIES)
+
+  link_libraries(protobuf)
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/Patches/protobuf-3.5.1.patch	Wed Mar 29 12:03:45 2023 +0200
@@ -0,0 +1,17 @@
+diff -urEb protobuf-3.5.1.orig/src/google/protobuf/stubs/io_win32.cc protobuf-3.5.1/src/google/protobuf/stubs/io_win32.cc
+--- protobuf-3.5.1.orig/src/google/protobuf/stubs/io_win32.cc	2023-03-26 20:13:45.095021011 +0200
++++ protobuf-3.5.1/src/google/protobuf/stubs/io_win32.cc	2023-03-26 20:19:19.932920102 +0200
+@@ -91,7 +91,12 @@
+ 
+ template <typename char_type>
+ bool null_or_empty(const char_type* s) {
+-  return s == nullptr || *s == 0;
++  /**
++   * "nullptr" is not known to Visual Studio 2008, because this is a
++   * C++11 construction, which shouldn't be present in protobuf 3.5.1
++   * that is supposed to comply with C++98.
++   **/
++  return s == NULL || *s == 0;
+ }
+ 
+ // Returns true if the path starts with a drive letter, e.g. "c:".
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/ProtocolBuffers/CMakeLists.txt	Wed Mar 29 12:03:45 2023 +0200
@@ -0,0 +1,149 @@
+# Orthanc - A Lightweight, RESTful DICOM Store
+# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+# Department, University Hospital of Liege, Belgium
+# Copyright (C) 2017-2023 Osimis S.A., Belgium
+# Copyright (C) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, 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/>.
+
+
+cmake_minimum_required(VERSION 2.8.3)
+
+project(ProtocolBuffers)
+
+set(ALLOW_DOWNLOADS ON)
+
+include(${CMAKE_SOURCE_DIR}/../CMake/DownloadPackage.cmake)
+include(${CMAKE_SOURCE_DIR}/../CMake/Compiler.cmake)
+
+include(${CMAKE_SOURCE_DIR}/ProtobufLibrary.cmake)
+
+set(PROTOBUF_COMPILER_SOURCES
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_enum.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_extension.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_file.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_map_field.cc  
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_message.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_service.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_field_base.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_helpers.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_map_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/importer.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_context.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_doc_comment.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_extension.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_extension_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_file.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_generator_factory.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_helpers.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_lazy_message_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_map_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_map_field_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_builder.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_builder_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_field_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_name_resolver.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_primitive_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_service.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_string_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_string_field_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_enum.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_extension.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_file.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_map_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_message.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+  #${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/js/embed.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/js/js_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/js/well_known_types_embed.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/main.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/parser.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/plugin.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/python/python_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.cc
+  )
+
+if (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
+  set_property(
+    SOURCE ${PROTOBUF_COMPILER_SOURCES}
+    PROPERTY COMPILE_DEFINITIONS "HAVE_PTHREAD=1"
+    )
+endif()
+
+add_executable(protoc
+  ${PROTOBUF_LIBRARY_SOURCES}
+  ${PROTOBUF_COMPILER_SOURCES}
+  )
+
+install(
+  TARGETS protoc
+  RUNTIME DESTINATION .
+  )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/ProtocolBuffers/NOTES.txt	Wed Mar 29 12:03:45 2023 +0200
@@ -0,0 +1,29 @@
+
+Version
+=======
+
+We use Google's Protocol Buffers version 3.5.1, as this is the last
+release to be compatible with C++98, which is mandatory for Visual
+Studio 2008 and Linux Standard Base.
+
+References:
+https://github.com/protocolbuffers/protobuf/releases/tag/v3.5.1
+https://github.com/protocolbuffers/protobuf/issues/2780
+
+
+Linux Standard Base
+===================
+
+$ mkdir lsb
+$ cd lsb
+$ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Release -DALLOW_DOWNLOADS=ON -DCMAKE_TOOLCHAIN_FILE=../../Toolchains/LinuxStandardBaseToolchain.cmake -G Ninja
+$ ninja
+
+
+MinGW for 32bits
+================
+
+$ mkdir w32
+$ cd w32
+$ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Release -DALLOW_DOWNLOADS=ON -DCMAKE_TOOLCHAIN_FILE=../../Toolchains/MinGW-W64-Toolchain32.cmake -G Ninja
+$ ninja
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Resources/ProtocolBuffers/ProtobufLibrary.cmake	Wed Mar 29 12:03:45 2023 +0200
@@ -0,0 +1,144 @@
+# 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) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+#
+# This program is free software: you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation, either version 3 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+
+set(PROTOBUF_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/protobuf-3.5.1)
+
+if (IS_DIRECTORY "${PROTOBUF_SOURCE_DIR}")
+  set(FirstRun OFF)
+else()
+  set(FirstRun ON)
+endif()
+
+DownloadPackage(
+  "ca0d9b243e649d398a6b419acd35103a"
+  "http://orthanc.uclouvain.be/third-party-downloads/protobuf-cpp-3.5.1.tar.gz"
+  "${CMAKE_CURRENT_BINARY_DIR}/protobuf-3.5.1")
+
+if (FirstRun)
+  # Apply the patches
+  execute_process(
+    COMMAND ${PATCH_EXECUTABLE} -p0 -N -i
+    ${CMAKE_CURRENT_LIST_DIR}/../Patches/protobuf-3.5.1.patch
+    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+    RESULT_VARIABLE Failure
+    )
+
+  if (Failure)
+    message(FATAL_ERROR "Error while patching a file")
+  endif()
+endif()
+
+include_directories(
+  ${PROTOBUF_SOURCE_DIR}/src
+  )
+  
+set(PROTOBUF_LIBRARY_SOURCES
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/any.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/any.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/api.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/arena.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/arenastring.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/descriptor.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/descriptor.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/descriptor_database.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/duration.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/dynamic_message.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/empty.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/extension_set.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/extension_set_heavy.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/field_mask.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_reflection.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_table_driven.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_table_driven_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_util.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/coded_stream.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/printer.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/strtod.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/tokenizer.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/map_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/message.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/message_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/reflection_ops.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/repeated_field.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/service.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/source_context.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/struct.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_arm64_gcc.h
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_arm_gcc.h
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/common.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/int128.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/io_win32.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/mathlimits.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/once.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/status.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/statusor.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/stringpiece.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/stringprintf.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/structurally_valid.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/strutil.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/substitute.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/time.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/bytestream.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/text_format.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/timestamp.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/type.pb.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/unknown_field_set.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/field_comparator.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/datapiece.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/error_listener.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/field_mask_utility.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/json_escaping.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/object_writer.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/proto_writer.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/type_info.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/utility.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/json_util.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/message_differencer.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/time_util.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/wire_format.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc
+  ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/wrappers.pb.cc
+  )
+
+if (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
+  set_property(
+    SOURCE ${PROTOBUF_LIBRARY_SOURCES}
+    PROPERTY COMPILE_DEFINITIONS "HAVE_PTHREAD=1"
+    )
+endif()
--- a/OrthancServer/CMakeLists.txt	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancServer/CMakeLists.txt	Wed Mar 29 12:03:45 2023 +0200
@@ -69,6 +69,11 @@
 ## Configuration of the Orthanc framework
 #####################################################################
 
+if (ENABLE_PLUGINS)
+  set(ENABLE_PROTOBUF ON)
+  set(ENABLE_PROTOBUF_COMPILER ON)
+endif()
+
 include(${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/CMake/VisualStudioPrecompiledHeaders.cmake)
 include(${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake)
 
@@ -361,8 +366,13 @@
 ## Build the core of Orthanc
 #####################################################################
 
+add_custom_target(AutogeneratedTarget
+  DEPENDS
+  ${AUTOGENERATED_SOURCES}
+  )
+
 # "CoreLibrary" contains all the third-party dependencies and the
-# content of the "Core" folder
+# content of the "OrthancFramework" folder
 add_library(CoreLibrary
   STATIC
   ${ORTHANC_CORE_PCH}
@@ -371,6 +381,8 @@
   ${AUTOGENERATED_SOURCES}
   )
 
+add_dependencies(CoreLibrary AutogeneratedTarget)
+
 if (LIBICU_LIBRARIES)
   target_link_libraries(CoreLibrary ${LIBICU_LIBRARIES})
 endif()
@@ -380,6 +392,30 @@
 ## Build the Orthanc server
 #####################################################################
 
+if (ENABLE_PLUGINS)
+  add_custom_command(
+    COMMAND
+    ${PROTOC_EXECUTABLE} ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancDatabasePlugin.proto --cpp_out=${AUTOGENERATED_DIR} -I${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc
+    DEPENDS
+    ProtobufCompiler
+    ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancDatabasePlugin.proto
+    OUTPUT
+    ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.cc
+    ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.h
+    )
+  
+  add_custom_target(OrthancDatabaseProtobuf
+    DEPENDS
+    ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.h
+    )
+
+  list(APPEND ORTHANC_SERVER_SOURCES
+    ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.cc
+    )
+else()
+  add_custom_target(OrthancDatabaseProtobuf)
+endif()
+
 add_library(ServerLibrary
   STATIC
   ${ORTHANC_SERVER_PCH}
@@ -387,7 +423,7 @@
   )
 
 # Ensure autogenerated code is built before building ServerLibrary
-add_dependencies(ServerLibrary CoreLibrary)
+add_dependencies(ServerLibrary CoreLibrary OrthancDatabaseProtobuf)
 
 add_executable(Orthanc
   ${CMAKE_SOURCE_DIR}/Sources/main.cpp
@@ -546,7 +582,6 @@
 
 if (ENABLE_PLUGINS AND (BUILD_DELAYED_DELETION OR BUILD_CONNECTIVITY_CHECKS))
   include(ExternalProject)
-
 endif()
 
 
@@ -825,8 +860,9 @@
 if (ENABLE_PLUGINS)
   install(
     FILES
-    ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCPlugin.h 
-    ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCDatabasePlugin.h 
+    ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCPlugin.h
+    ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCDatabasePlugin.h
+    ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancDatabasePlugin.proto
     DESTINATION include/orthanc
     )
 endif()
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp	Wed Mar 29 12:03:45 2023 +0200
@@ -1021,14 +1021,6 @@
     }
 
 
-    virtual bool IsExistingResource(int64_t internalId) ORTHANC_OVERRIDE
-    {
-      int32_t existing;
-      CheckSuccess(that_.backend_.isExistingResource(&existing, that_.payload_, internalId));
-      return (existing != 0);
-    }
-
-
     virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE
     {
       int32_t isProtected;
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Wed Mar 29 12:03:45 2023 +0200
@@ -594,15 +594,6 @@
     }
 
     
-    virtual bool IsExistingResource(int64_t internalId) ORTHANC_OVERRIDE
-    {
-      uint8_t b;
-      CheckSuccess(that_.backend_.isExistingResource(transaction_, &b, internalId));
-      CheckNoEvent();
-      return (b != 0);
-    }
-
-    
     virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE
     {
       uint8_t b;
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Wed Mar 29 12:03:45 2023 +0200
@@ -17,7 +17,7 @@
  *    - Possibly register its callback for received DICOM instances using ::OrthancPluginRegisterOnStoredInstanceCallback().
  *    - Possibly register its callback for changes to the DICOM store using ::OrthancPluginRegisterOnChangeCallback().
  *    - Possibly register a custom storage area using ::OrthancPluginRegisterStorageArea2().
- *    - Possibly register a custom database back-end area using OrthancPluginRegisterDatabaseBackendV3().
+ *    - Possibly register a custom database back-end area using OrthancPluginRegisterDatabaseBackendV4().
  *    - Possibly register a handler for C-Find SCP using OrthancPluginRegisterFindCallback().
  *    - Possibly register a handler for C-Find SCP against DICOM worklists using OrthancPluginRegisterWorklistCallback().
  *    - Possibly register a handler for C-Move SCP using OrthancPluginRegisterMoveCallback().
@@ -535,7 +535,8 @@
     _OrthancPluginService_StorageAreaRead = 5004,
     _OrthancPluginService_StorageAreaRemove = 5005,
     _OrthancPluginService_RegisterDatabaseBackendV3 = 5006,  /* New in Orthanc 1.9.2 */
-
+    _OrthancPluginService_RegisterDatabaseBackendV4 = 5007,  /* New in Orthanc 1.11.4 */
+    
     /* Primitives for handling images */
     _OrthancPluginService_GetImagePixelFormat = 6000,
     _OrthancPluginService_GetImageWidth = 6001,
@@ -9164,6 +9165,53 @@
   }
 
 
+  /**
+   * @brief 
+   * @ingroup Callbacks
+   **/
+  typedef OrthancPluginErrorCode (*OrthancPluginCallDatabaseBackendV4) (
+    OrthancPluginMemoryBuffer64* response,
+    void* backend,
+    const void* request,
+    uint64_t requestSize);
+
+  /**
+   * @brief 
+   * @ingroup Callbacks
+   **/
+  typedef void (*OrthancPluginFinalizeDatabaseBackendV4) (void* backend);
+
+  typedef struct
+  {
+    void*                                   backend;
+    OrthancPluginCallDatabaseBackendV4      operations;
+    OrthancPluginFinalizeDatabaseBackendV4  finalize;
+  } _OrthancPluginRegisterDatabaseBackendV4;
+
+  /**
+   * Register a custom database back-end.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param operations Access to the operations of the custom database backend.
+   * @param finalize Callback to deallocate the custom database backend.
+   * @param backend Pointer to the custom database backend.
+   * @return 0 if success, other value if error.
+   * @ingroup Callbacks
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterDatabaseBackendV4(
+    OrthancPluginContext*                   context,
+    void*                                   backend,
+    OrthancPluginCallDatabaseBackendV4      operations,
+    OrthancPluginFinalizeDatabaseBackendV4  finalize)
+  {
+    _OrthancPluginRegisterDatabaseBackendV4 params;
+    params.backend = backend;
+    params.operations = operations;
+    params.finalize = finalize;
+
+    return context->InvokeService(context, _OrthancPluginService_RegisterDatabaseBackendV4, &params);
+  }
+
 #ifdef  __cplusplus
 }
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto	Wed Mar 29 12:03:45 2023 +0200
@@ -0,0 +1,835 @@
+/**
+ * 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) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, 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/>.
+ **/
+
+
+syntax = "proto3";
+
+package Orthanc.DatabasePluginMessages;
+
+
+/**
+ * Data structures that are common with the Orthanc core.
+ **/
+
+message FileInfo {
+  string  uuid = 1;
+  int32   content_type = 2;      // opaque "FileContentType" in Orthanc
+  uint64  uncompressed_size = 3;
+  string  uncompressed_hash = 4;
+  int32   compression_type = 5;  // opaque "CompressionType" in Orthanc
+  uint64  compressed_size = 6;
+  string  compressed_hash = 7;
+}
+
+enum ResourceType {
+  RESOURCE_PATIENT = 0;
+  RESOURCE_STUDY = 1;
+  RESOURCE_SERIES = 2;
+  RESOURCE_INSTANCE = 3;
+}
+
+enum ConstraintType {
+  CONSTRAINT_EQUAL = 0;
+  CONSTRAINT_SMALLER_OR_EQUAL = 1;
+  CONSTRAINT_GREATER_OR_EQUAL = 2;
+  CONSTRAINT_WILDCARD = 3;
+  CONSTRAINT_LIST = 4;
+}
+
+message ServerIndexChange {
+  int64         seq = 1;
+  int32         change_type = 2;   // opaque "ChangeType" in Orthanc
+  ResourceType  resource_type = 3;
+  string        public_id = 4;
+  string        date = 5;
+}
+
+message ExportedResource {
+  int64         seq = 1;
+  ResourceType  resource_type = 2;
+  string        public_id = 3;
+  string        modality = 4;
+  string        date = 5;
+  string        patient_id = 6;
+  string        study_instance_uid = 7;
+  string        series_instance_uid = 8;
+  string        sop_instance_uid = 9;
+}
+
+message DatabaseConstraint {
+  ResourceType     level = 1;
+  int32            tag = 2;
+  string           value = 3;
+  bool             is_identifier = 4;
+  ConstraintType   constraint = 5;
+  repeated string  values = 6;
+  bool             case_sensitive = 7;
+  bool             mandatory = 8;
+}
+
+
+/**
+ * Database-level operations.
+ **/
+
+enum DatabaseOperation {
+  OPERATION_OPEN = 0;
+  OPERATION_CLOSE = 1;
+  OPERATION_FLUSH_TO_DISK = 2;
+  OPERATION_HAS_FLUSH_TO_DISK = 3;
+  OPERATION_START_TRANSACTION = 4;
+  OPERATION_GET_DATABASE_VERSION = 5;
+  OPERATION_UPGRADE = 6;
+  OPERATION_HAS_REVISION_SUPPORT = 7;
+}
+
+enum TransactionType {
+  TRANSACTION_TYPE_READ_ONLY = 0;
+  TRANSACTION_TYPE_READ_WRITE = 1;
+}
+
+message Open {
+  message Request {
+  }
+  message Response {
+  }
+}
+
+message Close {
+  message Request {
+  }
+  message Response {
+  }
+}
+
+message FlushToDisk {
+  message Request {
+  }
+  message Response {
+  }
+}
+
+message TestFlushToDisk {
+  message Request {
+  }
+  message Response {
+    bool result = 1;
+  }
+}
+
+message StartTransaction {
+  message Request {
+    TransactionType type = 1;
+  }
+  message Response {
+    sfixed64 transaction = 1;
+  }
+}
+
+message GetDatabaseVersion {
+  message Request {
+  }
+  message Response {
+    uint32 version = 1;
+  }
+}
+
+message Upgrade {
+  message Request {
+    uint32 targetVersion = 1;
+    sfixed64 storageArea = 2;
+  }
+  message Response {
+  }
+}
+
+message TestRevisionsSupport {
+  message Request {
+  }
+  message Response {
+    bool result = 1;
+  }
+}
+
+
+message RequestDatabase {
+  sfixed64           database = 1;
+  DatabaseOperation  operation = 2;
+
+  Open.Request                  open = 100;
+  Close.Request                 close = 101;
+  FlushToDisk.Request           flush_to_disk = 102;
+  TestFlushToDisk.Request       test_flush_to_disk = 103;
+  StartTransaction.Request      start_transaction = 104;
+  GetDatabaseVersion.Request    get_database_version = 105;
+  Upgrade.Request               upgrade = 106;
+  TestRevisionsSupport.Request  test_revisions_support = 107;
+}
+
+message ResponseDatabase {
+  int32   error_code = 1;
+  string  error_description = 2;
+
+  Open.Response                  open = 100;
+  Close.Response                 close = 101;
+  FlushToDisk.Response           flush_to_disk = 102;
+  TestFlushToDisk.Response       test_flush_to_disk = 103;
+  StartTransaction.Response      start_transaction = 104;
+  GetDatabaseVersion.Response    get_database_version = 105;
+  Upgrade.Response               upgrade = 106;
+  TestRevisionsSupport.Response  test_revisions_support = 107;
+}
+
+
+/**
+ * Transaction-level operations.
+ **/
+
+enum TransactionOperation {
+  OPERATION_ROLLBACK = 0;
+  OPERATION_COMMIT = 1;
+  OPERATION_ADD_ATTACHMENT = 2;
+  OPERATION_CLEAR_CHANGES = 3;
+  OPERATION_CLEAR_EXPORTED_RESOURCES = 4;
+  OPERATION_DELETE_ATTACHMENT = 5;
+  OPERATION_DELETE_METADATA = 6;
+  OPERATION_DELETE_RESOURCE = 7;
+  OPERATION_GET_ALL_METADATA = 8;
+  OPERATION_GET_ALL_PUBLIC_IDS = 9;
+  OPERATION_GET_ALL_PUBLIC_IDS_LIMITS = 10;
+  OPERATION_GET_CHANGES = 11;
+  OPERATION_GET_CHILDREN_INTERNAL_ID = 12;
+  OPERATION_GET_CHILDREN_PUBLIC_ID = 13;
+  OPERATION_GET_EXPORTED_RESOURCES = 14;
+  OPERATION_GET_LAST_CHANGE = 15;
+  OPERATION_GET_LAST_EXPORTED_RESOURCE = 16;
+  OPERATION_GET_MAIN_DICOM_TAGS = 17;
+  OPERATION_GET_PUBLIC_ID = 18;
+  OPERATION_GET_RESOURCES_COUNT = 19;
+  OPERATION_GET_RESOURCE_TYPE = 20;
+  OPERATION_GET_TOTAL_COMPRESSED_SIZE = 21;
+  OPERATION_GET_TOTAL_UNCOMPRESSED_SIZE = 22;
+  OPERATION_IS_PROTECTED_PATIENT = 23;
+  OPERATION_LIST_AVAILABLE_ATTACHMENTS = 24;
+  OPERATION_LOG_CHANGE = 25;
+  OPERATION_LOG_EXPORTED_RESOURCE = 26;
+  OPERATION_LOOKUP_ATTACHMENT = 27;
+  OPERATION_LOOKUP_GLOBAL_PROPERTY = 28;
+  OPERATION_LOOKUP_METADATA = 29;
+  OPERATION_LOOKUP_PARENT = 30;
+  OPERATION_LOOKUP_RESOURCE = 31;
+  OPERATION_SELECT_PATIENT_TO_RECYCLE = 32;
+  OPERATION_SELECT_PATIENT_TO_RECYCLE_WITH_AVOID = 33;
+  OPERATION_SET_GLOBAL_PROPERTY = 34;
+  OPERATION_CLEAR_MAIN_DICOM_TAGS = 35;
+  OPERATION_SET_METADATA = 36;
+  OPERATION_SET_PROTECTED_PATIENT = 37;
+  OPERATION_IS_DISK_SIZE_ABOVE = 38;
+  OPERATION_LOOKUP_RESOURCES = 39;
+  OPERATION_CREATE_INSTANCE = 40;
+  OPERATION_SET_RESOURCES_CONTENT = 41;
+  OPERATION_GET_CHILDREN_METADATA = 42;
+  OPERATION_GET_LAST_CHANGE_INDEX = 43;
+  OPERATION_LOOKUP_RESOURCE_AND_PARENT = 44;
+}
+
+message Rollback {
+  message Request {
+  }
+  message Response {
+  }
+}
+
+message Commit {
+  message Request {
+    int64 fileSizeDelta = 1;
+  }
+  message Response {
+  }
+}
+
+message AddAttachment {
+  message Request {
+    int64 id = 1;
+    FileInfo attachment = 2;
+    int64 revision = 3;
+  }
+  message Response {
+  }
+}
+
+message ClearChanges {
+  message Request {
+  }
+  message Response {
+  }
+}
+
+message ClearExportedResources {
+  message Request {
+  }
+  message Response {
+  }
+}
+
+message DeleteAttachment {
+  message Request {
+    int64 id = 1;
+    int32 type = 2;
+  }
+  message Response {
+    FileInfo deleted_attachment = 1;
+  }
+}
+
+message DeleteMetadata {
+  message Request {
+    int64 id = 1;
+    int32 type = 2;
+  }
+  message Response {
+  }
+}
+
+message DeleteResource {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    message Resource {
+      ResourceType level = 1;
+      string public_id = 2;
+    }
+    repeated FileInfo deleted_attachments = 1;
+    repeated Resource deleted_resources = 2;
+    bool is_remaining_ancestor = 3;
+    Resource remaining_ancestor = 4;
+  }
+}
+
+message GetAllMetadata {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    message Metadata {
+      int32 type = 1;
+      string value = 2;
+    }
+    repeated Metadata metadata = 1;
+  }
+}
+
+message GetAllPublicIds {
+  message Request {
+    int32 resource_type = 1;
+  }
+  message Response {
+    repeated string ids = 1;
+  }
+}
+
+message GetAllPublicIdsWithLimits {
+  message Request {
+    int32  resource_type = 1;
+    uint64 since = 2;
+    uint32 limit = 3;
+  }
+  message Response {
+    repeated string ids = 1;
+  }
+}
+
+message GetChanges {
+  message Request {
+    uint64 since = 1;
+    uint32 limit = 2;
+  }
+  message Response {
+    repeated ServerIndexChange changes = 1;
+    bool done = 2;
+  }
+}
+
+message GetChildrenInternalId {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    repeated int64 ids = 1;
+  }
+}
+
+message GetChildrenPublicId {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    repeated string ids = 1;
+  }
+}
+
+message GetExportedResources {
+  message Request {
+    int64 since = 1;
+    uint32 limit = 2;
+  }
+  message Response {
+    repeated ExportedResource resources = 1;
+    bool done = 2;
+  }
+}
+
+message GetLastChange {
+  message Request {
+  }
+  message Response {
+    bool is_empty = 1;
+    ServerIndexChange change = 2;
+  }
+}
+
+message GetLastExportedResource {
+  message Request {
+  }
+  message Response {
+    bool is_empty = 1;
+    ExportedResource resource = 2;
+  }
+}
+
+message GetMainDicomTags {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    message Tag {
+      uint32 key = 1;
+      string value = 2;
+    }
+    repeated Tag tags = 1;
+  }
+}
+
+message GetPublicId {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    string id = 1;
+  }
+}
+
+message GetResourcesCount {
+  message Request {
+    ResourceType type = 1;
+  }
+  message Response {
+    uint64 count = 1;
+  }
+}
+
+message GetResourceType {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    ResourceType type = 1;
+  }
+}
+
+message GetTotalCompressedSize {
+  message Request {
+  }
+  message Response {
+    uint64 size = 1;
+  }
+}
+
+message GetTotalUncompressedSize {
+  message Request {
+  }
+  message Response {
+    uint64 size = 1;
+  }
+}
+
+message IsProtectedPatient {
+  message Request {
+    int64 patient_id = 1;
+  }
+  message Response {
+    bool protected = 1;
+  }
+}
+
+message ListAvailableAttachments {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    repeated int32 attachments = 1;
+  }
+}
+
+message LogChange {
+  message Request {
+    int64 id = 1;
+    ServerIndexChange change = 2;
+  }
+  message Response {
+  }
+}
+
+message LogExportedResource {
+  message Request {
+    ExportedResource resource = 1;
+  }
+  message Response {
+  }
+}
+
+message LookupAttachment {
+  message Request {
+    int64 id = 1;
+    int32 content_type = 2;
+  }
+  message Response {
+    bool found = 1;
+    FileInfo attachment = 2;
+    int64 revision = 3;
+  }
+}
+
+message LookupGlobalProperty {
+  message Request {
+    int32 property = 1;
+    bool shared = 2;
+  }
+  message Response {
+    bool found = 1;
+    string value = 2;
+  }
+}
+
+message LookupMetadata {
+  message Request {
+    int64 id = 1;
+    int32 metadata_type = 2;
+  }
+  message Response {
+    bool found = 1;
+    string value = 2;
+    int64 revision = 3;
+  }
+}
+
+message LookupParent {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+    bool found = 1;
+    int64 parent = 2;
+  }
+}
+
+message LookupResource {
+  message Request {
+    string public_id = 1;
+  }
+  message Response {
+    bool found = 1;
+    int64 internal_id = 2;
+    ResourceType type = 3;
+  }
+}
+
+message SelectPatientToRecycle {
+  message Request {
+  }
+  message Response {
+    bool found = 1;
+    int64 id = 2;
+  }
+}
+
+message SelectPatientToRecycleWithAvoid {
+  message Request {
+    int64 patient_id_to_avoid = 1;
+  }
+  message Response {
+    bool found = 1;
+    int64 id = 2;
+  }
+}
+
+message SetGlobalProperty {
+  message Request {
+    int32 property = 1;
+    bool shared = 2;
+    string value = 3;
+  }
+  message Response {
+  }
+}
+
+message ClearMainDicomTags {
+  message Request {
+    int64 id = 1;
+  }
+  message Response {
+  }
+}
+
+message SetMetadata {
+  message Request {
+    int64 id = 1;
+    int32 metadata_type = 2;
+    string value = 3;
+    int64 revision = 4;
+  }
+  message Response {
+  }
+}
+
+message SetProtectedPatient {
+  message Request {
+    int64 id = 1;
+    bool protected = 2;
+  }
+  message Response {
+  }
+}
+
+message IsDiskSizeAbove {
+  message Request {
+    uint64 threshold = 1;
+  }
+  message Response {
+    bool result = 1;
+  }
+}
+
+message LookupResources {
+  message Request {
+    repeated DatabaseConstraint lookup = 1;
+    ResourceType query_level = 2;
+    uint32 limit = 3;
+    bool retrieve_instances = 4;
+  }
+  message Response {
+    repeated string resources_ids = 1;
+    repeated string instances_ids = 2;  // Only filled if "retrieve_instances" is true
+  }
+}
+
+message CreateInstance {
+  message Request {
+    string patient = 1;
+    string study = 2;
+    string series = 3;
+    string instance = 4;
+  }
+  message Response {
+    bool is_new_instance = 1;
+    int64 instance_id = 2;
+
+    // The fields below are only set if "is_new_instance" is true
+    bool is_new_patient = 3;
+    bool is_new_study = 4;
+    bool is_new_series = 5;
+    int64 patient_id = 6;
+    int64 study_id = 7;
+    int64 series_id = 8;
+  }
+}
+
+message SetResourcesContent {
+  message Request {
+    message Tag {
+      int64 resource_id = 1;
+      bool is_identifier = 2;
+      uint32 key = 3;
+      string value = 4;
+    }
+
+    message Metadata {
+      int64 resource_id = 1;
+      int32 metadata = 2;
+      string value = 3;
+    }
+
+    bool is_new_resource = 1;
+    repeated Tag tags = 2;
+    repeated Metadata metadata = 3;
+  }
+  message Response {
+  }
+}
+
+message GetChildrenMetadata {
+  message Request {
+    int64 id = 1;
+    int32 metadata = 2;
+  }
+  message Response {
+    repeated string values = 1;
+  }
+}
+
+message GetLastChangeIndex {
+  message Request {
+  }
+  message Response {
+    int64 result = 1;
+  }
+}
+
+message LookupResourceAndParent {
+  message Request {
+    string public_id = 1;
+  }
+  message Response {
+    bool found = 1;
+    int64 id = 2;
+    ResourceType type = 3;
+    string parent_public_id = 4;
+  }
+}
+
+message RequestTransaction {
+  sfixed64              transaction = 1;
+  TransactionOperation  operation = 2;
+
+  Rollback.Request                        rollback = 100;
+  Commit.Request                          commit = 101;
+  AddAttachment.Request                   add_attachment = 102;
+  ClearChanges.Request                    clear_changes = 103;
+  ClearExportedResources.Request          clear_exported_resources = 104;
+  DeleteAttachment.Request                delete_attachment = 105;
+  DeleteMetadata.Request                  delete_metadata = 106;
+  DeleteResource.Request                  delete_resource = 107;
+  GetAllMetadata.Request                  get_all_metadata = 108;
+  GetAllPublicIds.Request                 get_all_public_ids = 109;
+  GetAllPublicIdsWithLimits.Request       get_all_public_ids_with_limits = 110;
+  GetChanges.Request                      get_changes = 111;
+  GetChildrenInternalId.Request           get_children_internal_id = 112;
+  GetChildrenPublicId.Request             get_children_public_id = 113;
+  GetExportedResources.Request            get_exported_resources = 114;
+  GetLastChange.Request                   get_last_change = 115;
+  GetLastExportedResource.Request         get_last_exported_resource = 116;
+  GetMainDicomTags.Request                get_main_dicom_tags = 117;
+  GetPublicId.Request                     get_public_id = 118;
+  GetResourcesCount.Request               get_resources_count = 119;
+  GetResourceType.Request                 get_resource_type = 120;
+  GetTotalCompressedSize.Request          get_total_compressed_size = 121;
+  GetTotalUncompressedSize.Request        get_total_uncompressed_size = 122;
+  IsProtectedPatient.Request              is_protected_patient = 123;
+  ListAvailableAttachments.Request        list_available_attachments = 124;
+  LogChange.Request                       log_change = 125;
+  LogExportedResource.Request             log_exported_resource = 126;
+  LookupAttachment.Request                lookup_attachment = 127;
+  LookupGlobalProperty.Request            lookup_global_property = 128;
+  LookupMetadata.Request                  lookup_metadata = 129;
+  LookupParent.Request                    lookup_parent = 130;
+  LookupResource.Request                  lookup_resource = 131;
+  SelectPatientToRecycle.Request          select_patient_to_recycle = 132;
+  SelectPatientToRecycleWithAvoid.Request select_patient_to_recycle_with_avoid = 133;
+  SetGlobalProperty.Request               set_global_property = 134;
+  ClearMainDicomTags.Request              clear_main_dicom_tags = 135;
+  SetMetadata.Request                     set_metadata = 136;
+  SetProtectedPatient.Request             set_protected_patient = 137;
+  IsDiskSizeAbove.Request                 is_disk_size_above = 138;
+  LookupResources.Request                 lookup_resources = 139;
+  CreateInstance.Request                  create_instance = 140;
+  SetResourcesContent.Request             set_resources_content = 141;
+  GetChildrenMetadata.Request             get_children_metadata = 142;
+  GetLastChangeIndex.Request              get_last_change_index = 143;
+  LookupResourceAndParent.Request         lookup_resource_and_parent = 144;
+}
+
+message ResponseTransaction {
+  int32   error_code = 1;
+  string  error_description = 2;
+
+  Rollback.Response                        rollback = 100;
+  Commit.Response                          commit = 101;
+  AddAttachment.Response                   add_attachment = 102;
+  ClearChanges.Response                    clear_changes = 103;
+  ClearExportedResources.Response          clear_exported_resources = 104;
+  DeleteAttachment.Response                delete_attachment = 105;
+  DeleteMetadata.Response                  delete_metadata = 106;
+  DeleteResource.Response                  delete_resource = 107;
+  GetAllMetadata.Response                  get_all_metadata = 108;
+  GetAllPublicIds.Response                 get_all_public_ids = 109;
+  GetAllPublicIdsWithLimits.Response       get_all_public_ids_with_limits = 110;
+  GetChanges.Response                      get_changes = 111;
+  GetChildrenInternalId.Response           get_children_internal_id = 112;
+  GetChildrenPublicId.Response             get_children_public_id = 113;
+  GetExportedResources.Response            get_exported_resources = 114;
+  GetLastChange.Response                   get_last_change = 115;
+  GetLastExportedResource.Response         get_last_exported_resource = 116;
+  GetMainDicomTags.Response                get_main_dicom_tags = 117;
+  GetPublicId.Response                     get_public_id = 118;
+  GetResourcesCount.Response               get_resources_count = 119;
+  GetResourceType.Response                 get_resource_type = 120;
+  GetTotalCompressedSize.Response          get_total_compressed_size = 121;
+  GetTotalUncompressedSize.Response        get_total_uncompressed_size = 122;
+  IsProtectedPatient.Response              is_protected_patient = 123;
+  ListAvailableAttachments.Response        list_available_attachments = 124;
+  LogChange.Response                       log_change = 125;
+  LogExportedResource.Response             log_exported_resource = 126;
+  LookupAttachment.Response                lookup_attachment = 127;
+  LookupGlobalProperty.Response            lookup_global_property = 128;
+  LookupMetadata.Response                  lookup_metadata = 129;
+  LookupParent.Response                    lookup_parent = 130;
+  LookupResource.Response                  lookup_resource = 131;
+  SelectPatientToRecycle.Response          select_patient_to_recycle = 132;
+  SelectPatientToRecycleWithAvoid.Response select_patient_to_recycle_with_avoid = 133;
+  SetGlobalProperty.Response               set_global_property = 134;
+  ClearMainDicomTags.Response              clear_main_dicom_tags = 135;
+  SetMetadata.Response                     set_metadata = 136;
+  SetProtectedPatient.Response             set_protected_patient = 137;
+  IsDiskSizeAbove.Response                 is_disk_size_above = 138;
+  LookupResources.Response                 lookup_resources = 139;
+  CreateInstance.Response                  create_instance = 140;
+  SetResourcesContent.Response             set_resources_content = 141;
+  GetChildrenMetadata.Response             get_children_metadata = 142;
+  GetLastChangeIndex.Response              get_last_change_index = 143;
+  LookupResourceAndParent.Response         lookup_resource_and_parent = 144;
+}
+
+enum RequestType {
+  REQUEST_DATABASE = 0;
+  REQUEST_TRANSACTION = 1;
+}
+
+message Request {
+  RequestType         type = 1;
+  RequestDatabase     request_database = 2;
+  RequestTransaction  request_transaction = 3;
+}
+
+message Response {
+  ResponseDatabase     response_database = 1;
+  ResponseTransaction  response_transaction = 2;
+}
--- a/OrthancServer/Sources/Database/IDatabaseWrapper.h	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancServer/Sources/Database/IDatabaseWrapper.h	Wed Mar 29 12:03:45 2023 +0200
@@ -42,7 +42,7 @@
   class IDatabaseWrapper : public boost::noncopyable
   {
   public:
-    struct CreateInstanceResult
+    struct CreateInstanceResult : public boost::noncopyable
     {
       bool     isNewPatient_;
       bool     isNewStudy_;
@@ -130,8 +130,6 @@
     
       virtual uint64_t GetTotalUncompressedSize() = 0;
 
-      virtual bool IsExistingResource(int64_t internalId) = 0;
-
       virtual bool IsProtectedPatient(int64_t internalId) = 0;
 
       virtual void ListAvailableAttachments(std::set<FileContentType>& target,
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Wed Mar 29 12:03:01 2023 +0200
+++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Wed Mar 29 12:03:45 2023 +0200
@@ -731,15 +731,6 @@
     }
 
 
-    virtual bool IsExistingResource(int64_t internalId) ORTHANC_OVERRIDE
-    {
-      SQLite::Statement s(db_, SQLITE_FROM_HERE, 
-                          "SELECT * FROM Resources WHERE internalId=?");
-      s.BindInt64(0, internalId);
-      return s.Step();
-    }
-
-
     virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE
     {
       SQLite::Statement s(db_, SQLITE_FROM_HERE,