changeset 198:a8ff820fb028

integration java-code-model->mainline
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 02 Jul 2024 19:06:54 +0200
parents 46a81ed6e843 (current diff) cf15599a1608 (diff)
children 3757a7b9e6f1
files
diffstat 84 files changed, 9262 insertions(+), 1140 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Jul 02 17:17:24 2024 +0200
+++ b/CMakeLists.txt	Tue Jul 02 19:06:54 2024 +0200
@@ -184,6 +184,7 @@
   Sources/PythonModule.cpp
   Sources/PythonObject.cpp
   Sources/PythonString.cpp
+  Sources/PythonThreadsAllower.cpp
   Sources/ReceivedInstanceCallback.cpp
   Sources/RestCallbacks.cpp
   Sources/StorageArea.cpp
@@ -215,6 +216,11 @@
   SOVERSION ${PLUGIN_VERSION}
   )
 
+configure_file(
+  Sources/Autogenerated/orthanc.pyi
+  ${CMAKE_CURRENT_BINARY_DIR}/orthanc.pyi
+  COPYONLY)
+
 install(
   TARGETS OrthancPython
   RUNTIME DESTINATION lib    # Destination for Windows
--- a/CodeAnalysis/Class.mustache	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/Class.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 {{#methods}}
 static PyObject *sdk_{{class_name}}_{{c_function}}(
@@ -29,8 +32,7 @@
 
 // Forward declaration of the custom methods
 {{#custom_methods}}
-extern PyObject *{{implementation}}(
-  sdk_{{class_name}}_Object* self, PyObject *args);
+extern PyObject *{{implementation}}(sdk_{{class_name}}_Object* self, PyObject *args);
 {{/custom_methods}}
 // End of forward declarations
 
@@ -42,9 +44,9 @@
     "Generated from C function {{c_function}}()" },
 {{/methods}}
 {{#custom_methods}}
-  { "{{method_name}}",
+  { "{{short_name}}",
     (PyCFunction) {{implementation}}, METH_VARARGS,
-    "Generated from C function {{sdk_function}}()" },
+    "Implemented in C++ function {{implementation}}()" },
 {{/custom_methods}}
   { NULL }  /* Sentinel */
 };
--- a/CodeAnalysis/ClassMethods.mustache	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/ClassMethods.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 {{#methods}}
 static PyObject *sdk_{{class_name}}_{{c_function}}(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CodeAnalysis/CustomFunctions.json	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,44 @@
+[
+  {
+    "short_name" : "RegisterRestCallback",
+    "implementation" : "RegisterRestCallback",
+    "documentation" : {
+      "description" : [ "Register a REST callback." ],
+      "args" : {
+        "pathRegularExpression" : "Regular expression for the URI. May contain groups.",
+        "callback" : "The callback function to handle the REST call."
+      }
+    },
+    "args" : [
+      {
+        "sdk_name" : "pathRegularExpression",
+        "sdk_type" : "const char *"
+      },
+      {
+        "sdk_name" : "callback",
+        "sdk_type" : "Callable",
+        "callable_type" : "typing.Callable[[RestOutput, str], None]"
+      }
+    ],
+    "return_sdk_type" : "void"
+  },
+
+  {
+    "short_name" : "RegisterOnChangeCallback",
+    "implementation" : "RegisterOnChangeCallback",
+    "documentation" : {
+      "description" : [ "Register a callback to monitor changes." ],
+      "args" : {
+        "callback" : "The callback function."
+      }
+    },
+    "args" : [
+      {
+        "sdk_name" : "callback",
+        "sdk_type" : "Callable",
+        "callable_type" : "typing.Callable[[ChangeType, ResourceType, str], None]"
+      }
+    ],
+    "return_sdk_type" : "void"
+  }
+]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CodeAnalysis/CustomMethods.json	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,69 @@
+{
+  "OrthancPluginFindQuery" : [
+    {
+      "short_name" : "GetFindQueryTagGroup",
+      "implementation" : "GetFindQueryTagGroup",
+      "documentation" : {
+        "description" : [ "This function returns the group of one DICOM tag in the given C-Find query." ],
+        "args" : {
+          "index" : "The index of the tag of interest."
+        },
+        "return" : "The value of the group."
+      },
+      "args" : [
+        {
+          "sdk_name" : "index",
+          "sdk_type" : "uint32_t"
+        }
+      ],
+      "return_sdk_type" : "uint16_t"
+    },
+
+    {
+      "short_name" : "GetFindQueryTagElement",
+      "implementation" : "GetFindQueryTagElement",
+      "documentation" : {
+        "description" : [ "This function returns the element of one DICOM tag in the given C-Find query." ],
+        "args" : {
+          "index" : "The index of the tag of interest."
+        },
+        "return" : "The value of the element."
+      },
+      "args" : [
+        {
+          "sdk_name" : "index",
+          "sdk_type" : "uint32_t"
+        }
+      ],
+      "return_sdk_type" : "uint16_t"
+    }
+  ],
+
+  "OrthancPluginDicomInstance" : [
+    {
+      "short_name" : "GetInstanceData",
+      "implementation" : "GetInstanceData",
+      "documentation" : {
+        "description" : [ "Get the content of the DICOM instance." ],
+        "return" : "The DICOM data."
+      },
+      "args" : [
+      ],
+      "return_sdk_type" : "OrthancPluginMemoryBuffer *"
+    }
+  ],
+
+  "OrthancPluginImage" : [
+    {
+      "short_name" : "GetImageBuffer",
+      "implementation" : "GetImageBuffer",
+      "documentation" : {
+        "description" : [ "This function returns a pointer to the memory buffer that contains the pixels of the image." ],
+        "return" : "The pixel data."
+      },
+      "args" : [
+      ],
+      "return_sdk_type" : "OrthancPluginMemoryBuffer *"
+    }
+  ]
+}
--- a/CodeAnalysis/Dockerfile	Tue Jul 02 17:17:24 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-FROM ubuntu:18.04
-
-RUN export DEBIAN_FRONTEND=noninteractive
-RUN apt-get --assume-yes update
-RUN apt-get --assume-yes install build-essential
-RUN apt-get --assume-yes install python-clang-4.0
-RUN apt-get --assume-yes install python-pip
-RUN apt-get --assume-yes install clang-4.0
-
-# force pystache 0.5.0 (last version supported for python 2.7)
-RUN pip install pystache==0.5.0
-
-RUN mkdir /source
-RUN mkdir /target
-RUN mkdir /CodeAnalysis
-COPY *.mustache /CodeAnalysis/
-COPY *.py /CodeAnalysis/
-
-ENTRYPOINT ["python2"]
-CMD ["./CodeAnalysis/ParseOrthancSDK.py", "--libclang=libclang-4.0.so.1", "--source", "source/OrthancCPlugin.h", "--target", "target/"]
--- a/CodeAnalysis/Enumeration.mustache	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/Enumeration.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/CodeAnalysis/FunctionBody.mustache	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/FunctionBody.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -9,13 +9,28 @@
     return NULL;
   }
 {{/has_args}}
+{{#args}}{{#check_object_type}}
+  if ({{name}} != Py_None && Py_TYPE({{name}}) != Get{{check_object_type}}Type())
+  {
+    PyErr_SetString(PyExc_TypeError, "Invalid orthanc.{{check_object_type}} object");
+    return NULL;
+  }
+{{/check_object_type}}{{/args}}
 {{#return_long}}
-  long value = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  }
   {{#args}}{{release}}{{/args}}
   return PyLong_FromLong(value);
 {{/return_long}}
 {{#return_static_string}}
-  const char* s = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  }
   {{#args}}{{release}}{{/args}}
   if (s == NULL)
   {
@@ -29,7 +44,10 @@
 {{/return_static_string}}
 {{#return_dynamic_string}}
   OrthancPlugins::OrthancString s;
-  s.Assign({{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}}));
+  {
+    PythonThreadsAllower allower;
+    s.Assign({{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}}));
+  }
   {{#args}}{{release}}{{/args}}
   if (s.GetContent() == NULL)
   {
@@ -42,14 +60,21 @@
   }
 {{/return_dynamic_string}}
 {{#return_void}}
-  {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  {
+    PythonThreadsAllower allower;
+    {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  }
   {{#args}}{{release}}{{/args}}
 
   Py_INCREF(Py_None);
   return Py_None;
 {{/return_void}}
 {{#return_error}}
-  OrthancPluginErrorCode code = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  }
   {{#args}}{{release}}{{/args}}
 
   if (code == OrthancPluginErrorCode_Success)
@@ -65,7 +90,11 @@
 {{/return_error}}
 {{#return_object}}
   // This is the case of a constructor
-  {{return_object}}* obj = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  {{return_object}}* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  }
   {{#args}}{{release}}{{/args}}
   if (obj == NULL)
   {
@@ -82,7 +111,11 @@
 {{/return_object}}
 {{#return_bytes}}
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = {{c_function}}(OrthancPlugins::GetGlobalContext(), *buffer{{self}}{{call_args}});
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = {{c_function}}(OrthancPlugins::GetGlobalContext(), *buffer{{self}}{{call_args}});
+  }
   {{#args}}{{release}}{{/args}}
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -95,7 +128,11 @@
   }
 {{/return_bytes}}
 {{#return_enumeration}}
-  {{return_enumeration}} value = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  {{return_enumeration}} value;
+  {
+    PythonThreadsAllower allower;
+    value = {{c_function}}(OrthancPlugins::GetGlobalContext(){{self}}{{call_args}});
+  }
   {{#args}}{{release}}{{/args}}
   return PyLong_FromLong(value);
 {{/return_enumeration}}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CodeAnalysis/FunctionDocumentation.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,22 @@
+{{#documentation.short_description}}
+# {{documentation.short_description}}
+{{/documentation.short_description}}
+def {{short_name}}({{#self}}self{{#documentation.has_args}}, {{/documentation.has_args}}{{/self}}{{documentation.args_declaration}}) -> {{documentation.return_type}}:
+    """
+{{#documentation.description}}
+    {{text}}
+{{/documentation.description}}
+{{#documentation.has_args}}
+
+    Args:
+      {{#documentation.args}}
+      {{name}} ({{type}}): {{text}}
+      {{/documentation.args}}
+{{/documentation.has_args}}
+{{#documentation.has_return}}
+
+    Returns:
+      {{documentation.return_type}}: {{documentation.return_text}}
+{{/documentation.has_return}}
+    """
+    ...
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CodeAnalysis/GenerateOrthancSDK.py	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,469 @@
+#!/usr/bin/env python3
+
+##
+## Python plugin for Orthanc
+## Copyright (C) 2020-2023 Osimis S.A., Belgium
+## Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+## Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+##
+## This program is free software: you can redistribute it and/or
+## modify it under the terms of the GNU Affero 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
+## Affero General Public License for more details.
+##
+## You should have received a copy of the GNU Affero General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+
+import argparse
+import json
+import os
+import sys
+import pystache
+
+ROOT = os.path.dirname(os.path.realpath(sys.argv[0]))
+
+
+##
+## Parse the command-line arguments
+##
+
+parser = argparse.ArgumentParser(description = 'Generate Python code to wrap the Orthanc SDK.')
+parser.add_argument('--model',
+                    default = os.path.join(os.path.dirname(__file__),
+                                           '../Resources/Orthanc/Sdk-1.10.0/CodeModel.json'),
+                    help = 'Input code model, as generated by the orthanc-java project')
+parser.add_argument('--classes',
+                    default = os.path.join(os.path.dirname(__file__),
+                                           '../Resources/Orthanc/Sdk-1.10.0/ClassDocumentation.json'),
+                    help = 'Input description of classes, as defined in the orthanc-java project')
+parser.add_argument('--target',
+                    default = os.path.join(os.path.dirname(__file__),
+                                           '../Sources/Autogenerated'),
+                    help = 'Target folder')
+
+args = parser.parse_args()
+
+
+
+##
+## Configuration of the custom primitives that are manually
+## implemented (not autogenerated)
+##
+
+TARGET = os.path.realpath(args.target)
+
+
+with open(os.path.join(ROOT, 'CustomMethods.json'), 'r') as f:
+    CUSTOM_METHODS = json.loads(f.read())
+
+with open(os.path.join(ROOT, 'CustomFunctions.json'), 'r') as f:
+    CUSTOM_FUNCTIONS = json.loads(f.read())
+
+
+partials = {}
+
+with open(os.path.join(ROOT, 'FunctionBody.mustache'), 'r') as f:
+    partials['function_body'] = f.read()
+
+with open(os.path.join(ROOT, 'FunctionDocumentation.mustache'), 'r') as f:
+    partials['function_documentation'] = f.read()
+
+renderer = pystache.Renderer(
+    escape = lambda u: u,  # No escaping
+    partials = partials,
+)
+
+
+
+with open(args.model, 'r') as f:
+    model = json.loads(f.read())
+
+with open(args.classes, 'r') as f:
+    classes_description = json.loads(f.read())
+
+
+def ToUpperCase(name):
+    s = ''
+    for i in range(len(name)):
+        if name[i].isupper():
+            if len(s) == 0:
+                s += name[i]
+            elif name[i - 1].islower():
+                s += '_' + name[i]
+            elif (i + 1 < len(name) and
+                  name[i - 1].islower() and
+                  name[i + 1].isupper()):
+                s += '_' + name[i]
+            else:
+                s += name[i]
+        else:
+            s += name[i].upper()
+    return s
+
+
+def ToLowerCase(name):
+    s = ''
+    for i in range(len(name)):
+        if (name[i].isupper() and
+            len(s) != 0):
+            s += '_'
+        s += name[i].lower()
+    return s
+
+
+def GetShortName(name):
+    if not name.startswith('OrthancPlugin'):
+        raise Exception()
+    else:
+        return name[len('OrthancPlugin'):]
+
+
+
+ORTHANC_TO_PYTHON_NUMERIC_TYPES = {
+    # https://docs.python.org/3/c-api/arg.html#numbers
+    # https://en.wikipedia.org/wiki/C_data_types
+    'uint8_t' : {
+        'type' : 'unsigned char',
+        'format' : 'b',
+        },
+    'int32_t' : {
+        'type' : 'long int',
+        'format' : 'l',
+        },
+    'uint16_t' : {
+        'type' : 'unsigned short',
+        'format' : 'H',
+        },
+    'uint32_t' : {
+        'type' : 'unsigned long',
+        'format' : 'k',
+        },
+    'uint64_t' : {
+        'type' : 'unsigned long long',
+        'format' : 'K',
+        },
+    'float' : {
+        'type' : 'float',
+        'format' : 'f',
+        }
+    }
+
+
+def DocumentFunction(f):
+    documentation = {}
+    description = f['documentation'].get('description', [])
+    if len(description) > 0:
+        documentation['short_description'] = description[0].split('.') [0]
+    documentation['description'] = map(lambda x: { 'text' : x }, description)
+
+    args_declaration = []
+    args_documentation = []
+    for a in f['args']:
+        arg_name = ToLowerCase(a['sdk_name'])
+        if a['sdk_type'] == 'const char *':
+            arg_type = 'str'
+        elif a['sdk_type'] == 'float':
+            arg_type = 'float'
+        elif a['sdk_type'] in [ 'const_void_pointer_with_size', 'const void *' ]:
+            arg_type = 'bytes'
+        elif a['sdk_type'] == 'enumeration':
+            arg_type = GetShortName(a['sdk_enumeration'])
+        elif a['sdk_type'] == 'const_object':
+            arg_type = GetShortName(a['sdk_class'])
+        elif a['sdk_type'] in [ 'int32_t', 'uint32_t', 'uint8_t', 'uint16_t', 'uint64_t' ]:
+            arg_type = 'int'
+        elif a['sdk_type'] == 'Callable':
+            arg_type = a['callable_type']
+        else:
+            raise Exception('Argument type not implemented: %s' % a['sdk_type'])
+        args_declaration.append('%s: %s' % (arg_name, arg_type))
+        args_documentation.append({
+            'name' : arg_name,
+            'type' : arg_type,
+            'text' : f['documentation']['args'] [a['sdk_name']],
+        })
+
+    documentation['args_declaration'] = ', '.join(args_declaration)
+    documentation['args'] = args_documentation
+    documentation['has_args'] = len(args_documentation) > 0
+    documentation['has_return'] = True
+
+    if f['return_sdk_type'] == 'enumeration':
+        if f['return_sdk_enumeration'] == 'OrthancPluginErrorCode':
+            documentation['has_return'] = False
+            documentation['return_type'] = 'None'
+        else:
+            documentation['return_type'] = GetShortName(f['return_sdk_enumeration'])
+    elif f['return_sdk_type'] == 'object':
+        documentation['return_type'] = GetShortName(f['return_sdk_class'])
+    elif f['return_sdk_type'] == 'void':
+        documentation['has_return'] = False
+        documentation['return_type'] = 'None'
+    elif f['return_sdk_type'] == 'OrthancPluginMemoryBuffer *':
+        documentation['return_type'] = 'bytes'
+    elif f['return_sdk_type'] in [ 'char *', 'const char *' ]:
+        documentation['return_type'] = 'str'
+    elif f['return_sdk_type'] in [ 'int32_t', 'uint32_t', 'uint16_t', 'int64_t' ]:
+        documentation['return_type'] = 'int'
+    else:
+        raise Exception('Return type not implemented: %s' % f['return_sdk_type'])
+
+    if documentation['has_return']:
+        documentation['return_text'] = f['documentation']['return']
+
+    return documentation
+
+
+def FormatFunction(f):
+    answer = {
+        'c_function' : f['c_function'],
+        'short_name' : GetShortName(f['c_function']),
+        'has_args' : len(f['args']) > 0,
+        'count_args' : len(f['args']),
+    }
+
+    tuple_format = ''
+    tuple_target = []
+    call_args = []
+    args = []
+
+    for arg in f['args']:
+        # https://docs.python.org/3/c-api/arg.html
+        if arg['sdk_type'] in [ 'const void *', 'const_void_pointer_with_size' ]:
+            args.append({
+                'name' : arg['name'],
+                'python_type' : 'Py_buffer',
+                'release' : 'PyBuffer_Release(&%s);' % arg['name'],
+            })
+            tuple_format += 's*'
+        elif arg['sdk_type'] == 'const char *':
+            args.append({
+                'name' : arg['name'],
+                'python_type' : 'const char*',
+                'initialization' : ' = NULL',
+            })
+            tuple_format += 's'
+        elif arg['sdk_type'] == 'enumeration':
+            args.append({
+                'name' : arg['name'],
+                'python_type' : 'long int',
+                'initialization' : ' = 0',
+            })
+            tuple_format += 'l'
+        elif arg['sdk_type'] == 'const_object':
+            args.append({
+                'name' : arg['name'],
+                'python_type' : 'PyObject*',
+                'initialization' : ' = NULL',
+                'check_object_type' : arg['sdk_class'],
+            })
+            tuple_format += 'O'
+        elif arg['sdk_type'] in ORTHANC_TO_PYTHON_NUMERIC_TYPES:
+            t = ORTHANC_TO_PYTHON_NUMERIC_TYPES[arg['sdk_type']]
+            args.append({
+                'name' : arg['name'],
+                'python_type' : t['type'],
+                'initialization' : ' = 0',
+            })
+            tuple_format += t['format']
+        elif arg['sdk_type'] == 'Callable':
+            # This is only used to generate the documentation file "orthanc.pyi"
+            args.append({
+                'name' : arg['name'],
+            })
+            tuple_format += 'O'
+        else:
+            print('Ignoring function with unsupported argument type: %s(), type = %s' % (f['c_function'], arg['sdk_type']))
+            return None
+
+        tuple_target.append('&' + arg['name'])
+
+        if arg['sdk_type'] == 'const void *':
+            call_args.append(arg['name'] + '.buf')
+        elif arg['sdk_type'] == 'const_void_pointer_with_size':
+            call_args.append(arg['name'] + '.buf')
+            call_args.append(arg['name'] + '.len')
+        elif arg['sdk_type'] == 'enumeration':
+            call_args.append('static_cast<%s>(%s)' % (arg['sdk_enumeration'], arg['name']))
+        elif arg['sdk_type'] == 'const_object':
+            call_args.append('%s == Py_None ? NULL : reinterpret_cast<sdk_%s_Object*>(%s)->object_' % (
+                arg['name'], arg['sdk_class'], arg['name']))
+        else:
+            call_args.append(arg['name'])
+
+    answer['args'] = args
+
+    if f['return_sdk_type'] == 'void':
+        answer['return_void'] = True
+    elif f['return_sdk_type'] in [ 'int32_t', 'uint32_t', 'int64_t' ]:
+        answer['return_long'] = True
+    elif f['return_sdk_type'] == 'OrthancPluginMemoryBuffer *':
+        answer['return_bytes'] = True
+    elif f['return_sdk_type'] == 'enumeration':
+        if f['return_sdk_enumeration'] == 'OrthancPluginErrorCode':
+            answer['return_error'] = True
+        else:
+            answer['return_enumeration'] = f['return_sdk_enumeration']
+    elif f['return_sdk_type'] == 'char *':
+        answer['return_dynamic_string'] = True
+    elif f['return_sdk_type'] == 'const char *':
+        answer['return_static_string'] = True
+    elif f['return_sdk_type'] == 'object':
+        answer['return_object'] = f['return_sdk_class']
+    else:
+        print('Ignoring function with unsupported return type: %s(), type = %s' % (f['c_function'], f['return_sdk_type']))
+        return None
+
+    answer['tuple_format'] = ', '.join([ '"' + tuple_format + '"' ] + tuple_target)
+
+    if 'documentation' in f:
+        answer['documentation'] = DocumentFunction(f)
+
+    if len(call_args) > 0:
+        answer['call_args'] = ', ' + ', '.join(call_args)
+
+    return answer
+
+
+
+globalFunctions = []
+customFunctions = []
+
+for f in model['global_functions']:
+    g = FormatFunction(f)
+    if g != None:
+        globalFunctions.append(g)
+
+for f in CUSTOM_FUNCTIONS:
+    f['documentation'] = DocumentFunction(f)
+    customFunctions.append(f)
+
+
+enumerations = []
+
+with open(os.path.join(ROOT, 'Enumeration.mustache'), 'r') as f:
+    ENUMERATION_TEMPLATE = f.read()
+
+for e in model['enumerations']:
+    values = []
+    for value in e['values']:
+        values.append({
+            'key' : ToUpperCase(value['key']),
+            'value' : value['value'],
+            'documentation' : value['documentation'],
+        })
+
+    enumerations.append({
+        'name' : e['name'],
+        'short_name' : GetShortName(e['name']),
+        'path' : 'sdk_%s.impl.h' % e['name'],
+        'values' : values,
+        'documentation' : e['documentation'],
+    })
+
+    path = 'sdk_%s.impl.h' % e['name']
+
+    with open(os.path.join(TARGET, path), 'w') as f:
+        f.write(pystache.render(ENUMERATION_TEMPLATE, {
+            'name' : e['name'],
+            'short_name' : GetShortName(e['name']),
+            'values' : values,
+        }))
+
+
+classes = []
+
+for c in model['classes']:
+    methods = []
+
+    for m in c['methods']:
+        g = FormatFunction(m)
+        if g != None:
+            g['self'] = ', self->object_'
+            methods.append(g)
+
+    custom_methods = []
+
+    if c['name'] in CUSTOM_METHODS:
+        for custom_method in CUSTOM_METHODS[c['name']]:
+            custom_method['self'] = True   # Indicates that this is a method
+            custom_method['documentation'] = DocumentFunction(custom_method)
+            custom_methods.append(custom_method)
+
+    classes.append({
+        'description' : classes_description[c['name']],
+        'class_name' : c['name'],
+        'short_name' : GetShortName(c['name']),
+        'methods' : methods,
+        'custom_methods' : sorted(custom_methods, key = lambda x: x['short_name']),
+    })
+
+    if 'destructor' in c:
+        classes[-1]['destructor'] = c['destructor']
+
+
+
+
+with open(os.path.join(ROOT, 'Class.mustache'), 'r') as f:
+    with open(os.path.join(ROOT, 'ClassMethods.mustache'), 'r') as g:
+        classDefinition = f.read()
+        classMethods = g.read()
+
+        for c in classes:
+            with open(os.path.join(TARGET, 'sdk_%s.impl.h' % c['class_name']), 'w') as h:
+                h.write(renderer.render(classDefinition, c))
+            with open(os.path.join(TARGET, 'sdk_%s.methods.h' % c['class_name']), 'w') as h:
+                h.write(renderer.render(classMethods, c))
+
+
+sortedClasses = sorted(classes, key = lambda x: x['class_name'])
+sortedEnumerations = sorted(enumerations, key = lambda x: x['name'])
+sortedGlobalFunctions = sorted(globalFunctions, key = lambda x: x['c_function'])
+sortedCustomFunctions = sorted(customFunctions, key = lambda x: x['short_name'])
+
+with open(os.path.join(ROOT, 'GlobalFunctions.mustache'), 'r') as f:
+    with open(os.path.join(TARGET, 'sdk_GlobalFunctions.impl.h'), 'w') as h:
+        h.write(renderer.render(f.read(), {
+            'global_functions' : sortedGlobalFunctions,
+            'custom_functions' : sortedCustomFunctions,
+        }))
+
+with open(os.path.join(ROOT, 'sdk.cpp.mustache'), 'r') as f:
+    with open(os.path.join(TARGET, 'sdk.cpp'), 'w') as h:
+        h.write(renderer.render(f.read(), {
+            'classes' : sortedClasses,
+            'enumerations' : sortedEnumerations,
+            'global_functions' : sortedGlobalFunctions,
+            'custom_functions' : sortedCustomFunctions,
+        }))
+
+with open(os.path.join(ROOT, 'sdk.h.mustache'), 'r') as f:
+    with open(os.path.join(TARGET, 'sdk.h'), 'w') as h:
+        h.write(renderer.render(f.read(), {
+            'classes' : sortedClasses,
+        }))
+
+with open(os.path.join(ROOT, 'PythonDocumentation.mustache'), 'r') as f:
+    with open(os.path.join(TARGET, 'orthanc.pyi'), 'w') as h:
+        h.write(renderer.render(f.read(), {
+            'classes' : sortedClasses,
+            'enumerations' : sortedEnumerations,
+            'global_functions' : sortedGlobalFunctions,
+            'custom_functions' : sortedCustomFunctions,
+        }))
+
+
+countMethods = 0
+for c in sortedClasses:
+    countMethods += len(c['methods'])
+
+print('\nNumber of wrapped global functions: %d' % len(sortedGlobalFunctions + sortedCustomFunctions))
+print('Number of wrapped methods: %d\n' % countMethods)
+print('Total number of wrapped global functions or methods: %d\n' % (len(sortedGlobalFunctions + sortedCustomFunctions) + countMethods))
--- a/CodeAnalysis/GlobalFunctions.mustache	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/GlobalFunctions.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,16 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
+// Forward declaration of the custom global functions
+{{#custom_functions}}
+extern PyObject *{{implementation}}(PyObject* module, PyObject *args);
+{{/custom_functions}}
+// End of forward declarations
+
+
 {{#global_functions}}
 static PyObject* sdk_{{c_function}}(PyObject* module, PyObject* args)
 {
@@ -35,6 +45,10 @@
   { "{{short_name}}", sdk_{{c_function}}, METH_VARARGS,
     "Generated from C function {{c_function}}()" },
 {{/global_functions}}
+{{#custom_functions}}
+  { "{{short_name}}", {{implementation}}, METH_VARARGS,
+    "Implemented in C++ function {{implementation}}()" },
+{{/custom_functions}}
   { NULL, NULL }
 };
 
--- a/CodeAnalysis/ParseOrthancSDK.py	Tue Jul 02 17:17:24 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,578 +0,0 @@
-#!/usr/bin/env python3
-
-##
-## Python plugin for Orthanc
-## Copyright (C) 2020-2023 Osimis S.A., Belgium
-## Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
-## Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
-##
-## This program is free software: you can redistribute it and/or
-## modify it under the terms of the GNU Affero 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
-## Affero General Public License for more details.
-## 
-## You should have received a copy of the GNU Affero General Public License
-## along with this program. If not, see <http://www.gnu.org/licenses/>.
-##
-
-
-import argparse
-import clang.cindex
-import json
-import os
-import pprint
-import pystache
-import sys
-
-
-ROOT = os.path.dirname(os.path.realpath(sys.argv[0]))
-
-
-##
-## Configuration of the custom primitives that are manually
-## implemented (not autogenerated)
-##
-
-CUSTOM_FUNCTIONS = set([
-    'OrthancPluginCreateMemoryBuffer',
-    'OrthancPluginCreateDicom',
-    'OrthancPluginCreateImageAccessor',                # Replaced by "orthanc.CreateImageFromBuffer()"
-    'OrthancPluginFreeMemoryBuffer',
-    'OrthancPluginFreeString',
-    'OrthancPluginLookupDictionary',
-    'OrthancPluginRegisterFindCallback',
-    'OrthancPluginRegisterIncomingHttpRequestFilter',  # Implemented through v2
-    'OrthancPluginRegisterIncomingHttpRequestFilter2',
-    'OrthancPluginRegisterMoveCallback',
-    'OrthancPluginRegisterOnChangeCallback',
-    'OrthancPluginRegisterOnStoredInstanceCallback',
-    'OrthancPluginRegisterRestCallback',               # Implemented using OrthancPlugins::RegisterRestCallback
-    'OrthancPluginRegisterRestCallbackNoLock',         # Implemented using OrthancPlugins::RegisterRestCallback
-    'OrthancPluginRegisterWorklistCallback',
-    'OrthancPluginRegisterIncomingCStoreInstanceFilter',
-])
-
-CUSTOM_METHODS = [
-    {
-        'class_name' : 'OrthancPluginFindQuery',
-        'method_name' : 'GetFindQueryTagGroup',
-        'implementation' : 'GetFindQueryTagGroup',
-        'sdk_function' : 'OrthancPluginGetFindQueryTag',
-    },
-    {
-        'class_name' : 'OrthancPluginFindQuery',
-        'method_name' : 'GetFindQueryTagElement',
-        'implementation' : 'GetFindQueryTagElement',
-        'sdk_function' : 'OrthancPluginGetFindQueryTag',
-    },
-    {
-        'class_name' : 'OrthancPluginWorklistAnswers',
-        'method_name' : 'WorklistAddAnswer',
-        'implementation' : 'WorklistAddAnswer',
-        'sdk_function' : 'OrthancPluginWorklistAddAnswer',
-    },
-    {
-        'class_name' : 'OrthancPluginDicomInstance',
-        'method_name' : 'GetInstanceData',
-        'implementation' : 'GetInstanceData',
-        'sdk_function' : 'OrthancPluginGetInstanceData',
-    },    
-    {
-        'class_name' : 'OrthancPluginImage',
-        'method_name' : 'GetImageBuffer',
-        'implementation' : 'GetImageBuffer',
-        'sdk_function' : 'OrthancPluginGetImageBuffer',
-    },    
-]
-
-for method in CUSTOM_METHODS:
-    CUSTOM_FUNCTIONS.add(method['sdk_function'])
-
-
-##
-## Parse the command-line arguments
-##
-
-parser = argparse.ArgumentParser(description = 'Parse the Orthanc SDK.')
-parser.add_argument('--libclang',
-                    default = 'libclang-4.0.so.1',
-                    help = 'manually provides the path to the libclang shared library')
-parser.add_argument('--source',
-                    default = os.path.join(os.path.dirname(__file__),
-                                           '../Resources/Orthanc/Sdk-1.10.0/orthanc/OrthancCPlugin.h'),
-                    help = 'Input C++ file')
-parser.add_argument('--target', 
-                    default = os.path.join(os.path.dirname(__file__),
-                                           '../Sources/Autogenerated'),
-                    help = 'Target folder')
-
-args = parser.parse_args()
-
-
-
-if len(args.libclang) != 0:
-    clang.cindex.Config.set_library_file(args.libclang)
-
-index = clang.cindex.Index.create()
-
-tu = index.parse(args.source, [ ])
-
-TARGET = os.path.realpath(args.target)
-
-
-
-def ToUpperCase(name):
-    s = ''
-    for i in range(len(name)):
-        if name[i].isupper():
-            if len(s) == 0:
-                s += name[i]
-            elif name[i - 1].islower():
-                s += '_' + name[i]
-            elif (i + 1 < len(name) and
-                  name[i - 1].islower() and
-                  name[i + 1].isupper()):
-                s += '_' + name[i]
-            else:
-                s += name[i]
-        else:
-            s += name[i].upper()
-    return s
-
-
-
-with open(os.path.join(ROOT, 'Enumeration.mustache'), 'r') as f:
-    TEMPLATE = f.read()
-
-
-classes = {}
-enumerations = {}
-globalFunctions = []
-countAllFunctions = 0
-countSupportedFunctions = 0
-
-def IsSourceStringType(t):
-    return (t.kind == clang.cindex.TypeKind.POINTER and
-            t.get_pointee().kind == clang.cindex.TypeKind.CHAR_S and
-            t.get_pointee().is_const_qualified())
-
-def IsTargetStaticStringType(t):
-    return (t.kind == clang.cindex.TypeKind.POINTER and
-            t.get_pointee().kind == clang.cindex.TypeKind.CHAR_S and
-            t.get_pointee().is_const_qualified())
-
-def IsTargetDynamicStringType(t):
-    return (t.kind == clang.cindex.TypeKind.POINTER and
-            t.get_pointee().kind == clang.cindex.TypeKind.CHAR_S and
-            not t.get_pointee().is_const_qualified())
-
-def IsIntegerType(t):
-    return (t.kind == clang.cindex.TypeKind.INT or
-            t.spelling in [ 'int8_t', 'int16_t', 'int32_t', 'int64_t',
-                            'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t'])
-
-def IsFloatType(t):
-    return t.kind == clang.cindex.TypeKind.FLOAT
-
-def IsEnumerationType(t):
-    return (t.kind == clang.cindex.TypeKind.TYPEDEF and
-            t.spelling in enumerations)
-
-def IsTargetMemoryBufferType(t):
-    return (t.kind == clang.cindex.TypeKind.POINTER and
-            not t.get_pointee().is_const_qualified() and
-            t.get_pointee().spelling == 'OrthancPluginMemoryBuffer')    
-
-def IsSourceMemoryBufferType(t):
-    return (t.kind == clang.cindex.TypeKind.POINTER and
-            t.get_pointee().kind == clang.cindex.TypeKind.VOID and
-            t.get_pointee().is_const_qualified())
-
-def IsClassType(t):
-    return (t.kind == clang.cindex.TypeKind.POINTER and
-            ((t.get_pointee().is_const_qualified() and
-              t.get_pointee().spelling.startswith('const ') and
-              t.get_pointee().spelling[len('const '):] in classes) or
-             (not t.get_pointee().is_const_qualified() and
-              t.get_pointee().spelling in classes)))
-
-def IsSimpleSourceType(t):
-    return (IsSourceStringType(t) or
-            IsFloatType(t) or
-            IsIntegerType(t) or
-            IsEnumerationType(t) or
-            IsSourceMemoryBufferType(t))
-
-def IsVoidType(t):
-    return t.kind == clang.cindex.TypeKind.VOID
-
-def IsSupportedTargetType(t):
-    return (IsVoidType(t) or
-            IsIntegerType(t) or
-            IsEnumerationType(t) or
-            # Constructor of a class
-            (t.kind == clang.cindex.TypeKind.POINTER and
-             not t.get_pointee().is_const_qualified() and
-             t.get_pointee().spelling in classes) or
-            # "const char*" or "char*" outputs
-            (t.kind == clang.cindex.TypeKind.POINTER and
-             #not t.get_pointee().is_const_qualified() and
-             t.get_pointee().kind == clang.cindex.TypeKind.CHAR_S))
-
-def IsBytesArgument(args, index):
-    return (index + 1 < len(args) and
-            args[index].type.kind == clang.cindex.TypeKind.POINTER and
-            args[index].type.get_pointee().kind == clang.cindex.TypeKind.VOID and
-            args[index].type.get_pointee().is_const_qualified() and
-            args[index + 1].type.spelling == 'uint32_t')
-
-def CheckOnlySupportedArguments(args):
-    j = 0
-    while j < len(args):
-        if IsBytesArgument(args, j):
-            j += 2
-        elif IsSimpleSourceType(args[j].type):
-            j += 1
-        else:
-            return False
-    return True
-
-
-ORTHANC_TO_PYTHON_NUMERIC_TYPES = {
-    # https://docs.python.org/3/c-api/arg.html#numbers
-    'int' : {
-        'type' : 'int',
-        'format' : 'i',
-        },
-    'uint8_t' : {
-        'type' : 'unsigned char',
-        'format' : 'b',
-        },
-    'int32_t' : {
-        'type' : 'long int',
-        'format' : 'l',
-        },
-    'uint16_t' : {
-        'type' : 'unsigned short',
-        'format' : 'H',
-        },
-    'uint32_t' : {
-        'type' : 'unsigned long',
-        'format' : 'k',
-        },
-    'uint64_t' : {
-        'type' : 'unsigned long long',
-        'format' : 'K',
-        },
-    'float' : {
-        'type' : 'float',
-        'format' : 'f',
-        }
-    }
-
-
-def GenerateFunctionBodyTemplate(cFunction, result_type, args):
-    if not cFunction.startswith('OrthancPlugin'):
-        raise Exception()
-
-    func = {
-        'c_function' : cFunction,
-        'short_name' : cFunction[len('OrthancPlugin'):],
-        'args' : [],
-        'return_sdk_type' : result_type.spelling,
-    }
-    
-    if IsIntegerType(result_type):
-        func['return_long'] = True
-    elif IsTargetDynamicStringType(result_type):
-        func['return_dynamic_string'] = True
-    elif IsTargetStaticStringType(result_type):
-        func['return_static_string'] = True
-    elif IsVoidType(result_type):
-        func['return_void'] = True
-    elif result_type.spelling == 'OrthancPluginErrorCode':
-        func['return_error'] = True
-        func['return_sdk_type'] = 'enumeration'
-        func['return_sdk_enumeration'] = result_type.spelling
-    elif IsClassType(result_type):
-        func['return_object'] = result_type.get_pointee().spelling
-        func['return_sdk_type'] = 'object'
-        func['return_sdk_class'] = result_type.get_pointee().spelling
-    elif IsTargetMemoryBufferType(result_type):
-        func['return_bytes'] = True
-    elif IsEnumerationType(result_type):
-        func['return_enumeration'] = result_type.spelling
-        func['return_sdk_type'] = 'enumeration'
-        func['return_sdk_enumeration'] = result_type.spelling
-    else:
-        raise Exception('Not supported: %s' % result_type.spelling)
-
-    i = 0
-    while i < len(args):
-        a = {
-            'name' : 'arg%d' % i,
-            'sdk_type' : args[i].type.spelling,
-            'sdk_name' : args[i].spelling,
-            }
-
-        if (IsIntegerType(args[i].type) or
-            IsFloatType(args[i].type)):
-            t = ORTHANC_TO_PYTHON_NUMERIC_TYPES[args[i].type.spelling]
-            a['python_type'] = t['type']
-            a['python_format'] = t['format']
-            a['initialization'] = ' = 0'
-            a['orthanc_cast'] = 'arg%d' % i
-            func['args'].append(a)
-        elif IsSourceStringType(args[i].type):
-            a['python_type'] = 'const char*'
-            a['python_format'] = 's'
-            a['initialization'] = ' = NULL'
-            a['orthanc_cast'] = 'arg%d' % i
-            func['args'].append(a)
-        elif IsEnumerationType(args[i].type):
-            a['python_type'] = 'long int'
-            a['python_format'] = 'l'
-            a['initialization'] = ' = 0'
-            a['orthanc_cast'] = 'static_cast<%s>(arg%d)' % (args[i].type.spelling, i)
-            a['sdk_type'] = 'enumeration'
-            a['sdk_enumeration'] = args[i].type.spelling
-            func['args'].append(a)
-        elif IsBytesArgument(args, i):
-            a['python_type'] = 'Py_buffer'
-            # In theory, one should use "y*" (this is the recommended
-            # way to accept binary data). However, this is not
-            # available in Python 2.7
-            a['python_format'] = 's*'
-            a['orthanc_cast'] = 'arg%d.buf, arg%d.len' % (i, i)
-            a['release'] = 'PyBuffer_Release(&arg%d);' % i
-            a['sdk_type'] = 'const_void_pointer_with_size'
-            func['args'].append(a)
-            i += 1  # Skip the size argument
-        elif IsSourceMemoryBufferType(args[i].type):
-            a['python_type'] = 'Py_buffer'
-            a['python_format'] = 's*'
-            a['orthanc_cast'] = 'arg%d.buf' % i
-            a['release'] = 'PyBuffer_Release(&arg%d);' % i
-            func['args'].append(a)
-        else:
-            raise Exception('Not supported: %s, %s' % (cFunction, args[i].spelling))
-
-        i += 1
-        
-    func['tuple_format'] = '"%s", %s' % (
-        ''.join(map(lambda x: x['python_format'], func['args'])),
-        ', '.join(map(lambda x: '&' + x['name'], func['args'])))
-
-    if len(func['args']) > 0:
-        func['count_args'] = len(func['args'])
-        func['has_args'] = True
-        func['call_args'] = ', ' + ', '.join(map(lambda x: x['orthanc_cast'], func['args']))
-
-    return func
-             
-
-for node in tu.cursor.get_children():
-    if node.kind == clang.cindex.CursorKind.ENUM_DECL:
-        if node.type.spelling.startswith('OrthancPlugin'):
-            name = node.type.spelling
-
-            values = []
-            for item in node.get_children():
-                if (item.kind == clang.cindex.CursorKind.ENUM_CONSTANT_DECL and
-                    item.spelling.startswith(name + '_')):
-                    values.append({
-                        'key' : ToUpperCase(item.spelling[len(name)+1:]),
-                        'value' : item.enum_value
-                    })
-
-            path = 'sdk_%s.impl.h' % name
-            shortName = name[len('OrthancPlugin'):]
-
-            with open(os.path.join(TARGET, path), 'w') as f:
-                f.write(pystache.render(TEMPLATE, {
-                    'name' : name,
-                    'short_name' : shortName,
-                    'values' : values,
-                }))
-
-            enumerations[name] = {
-                'name' : name,
-                'path' : path,
-                'values' : values,
-            }
-
-    elif node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
-        if node.spelling.startswith('OrthancPlugin'):
-            #if node.spelling != 'OrthancPluginWorklistGetDicomQuery':
-            #    continue
-            shortName = node.spelling[len('OrthancPlugin'):]
-            
-            # Check that the first argument is the Orthanc context
-            args = list(filter(lambda x: x.kind == clang.cindex.CursorKind.PARM_DECL,
-                               node.get_children()))
-
-            if (len(args) == 0 or
-                args[0].type.kind != clang.cindex.TypeKind.POINTER or
-                args[0].type.get_pointee().spelling != 'OrthancPluginContext'):
-                print('Not in the Orthanc SDK: %s()' % node.spelling)
-                continue
-
-            # Discard the context from the arguments
-            countAllFunctions += 1
-            args = args[1:]
-
-            if node.spelling in CUSTOM_FUNCTIONS:
-                print('Ignoring custom function that is manually implemented: %s()' % node.spelling)
-                countSupportedFunctions += 1                
-
-            elif not IsSupportedTargetType(node.result_type):
-                print('*** UNSUPPORTED OUTPUT: %s' % node.spelling)
-            
-            elif (len(args) == 1 and
-                  IsClassType(args[0].type) and
-                  node.spelling.startswith('OrthancPluginFree')):
-                print('Destructor: %s' % node.spelling)
-                className = args[0].type.get_pointee().spelling
-                classes[className]['destructor'] = node.spelling
-                countSupportedFunctions += 1
-
-            elif CheckOnlySupportedArguments(args):
-                if IsClassType(node.result_type):
-                    print('Constructor: %s' % node.spelling)
-                else:
-                    print('Simple global function: %s => %s' % (node.spelling, node.result_type.spelling))
-
-                body = GenerateFunctionBodyTemplate(node.spelling, node.result_type, args)
-                globalFunctions.append(body)
-                countSupportedFunctions += 1
-
-            elif (len(args) >= 2 and
-                  IsTargetMemoryBufferType(args[0].type) and
-                  CheckOnlySupportedArguments(args[1:])):
-                print('Simple global function, returning bytes: %s' % node.spelling)
-
-                body = GenerateFunctionBodyTemplate(node.spelling, args[0].type, args[1:])
-                globalFunctions.append(body)
-                countSupportedFunctions += 1
-                
-            elif (IsClassType(args[0].type) and
-                  CheckOnlySupportedArguments(args[1:])):
-                className = args[0].type.get_pointee().spelling
-
-                print('Simple method of class %s: %s' % (className, node.spelling))
-                if node.spelling in CUSTOM_FUNCTIONS:
-                    raise Exception('Cannot overwrite an autogenerated method: %s()' % node.spelling)
-                
-                if className.startswith('const '):
-                    className = className[len('const '):]
-                
-                method = GenerateFunctionBodyTemplate(node.spelling, node.result_type, args[1:])
-                method['self'] = ', self->object_'
-                classes[className]['methods'].append(method)
-                countSupportedFunctions += 1
-
-            elif (len(args) >= 2 and
-                  IsTargetMemoryBufferType(args[0].type) and
-                  IsClassType(args[1].type) and
-                  CheckOnlySupportedArguments(args[2:])):
-                className = args[1].type.get_pointee().spelling
-
-                print('Simple method of class %s, returning bytes: %s' % (className, node.spelling))
-                if node.spelling in CUSTOM_FUNCTIONS:
-                    raise Exception('Cannot overwrite an autogenerated method: %s()' % node.spelling)
-                
-                if className.startswith('const '):
-                    className = className[len('const '):]
-
-                method = GenerateFunctionBodyTemplate(node.spelling, args[0].type, args[2:])
-                method['self'] = ', self->object_'
-                classes[className]['methods'].append(method)
-                countSupportedFunctions += 1
-            
-            else:
-                print('*** UNSUPPORTED INPUT: %s' % node.spelling)
-            
-
-
-    elif node.kind == clang.cindex.CursorKind.STRUCT_DECL:
-        if (node.spelling.startswith('_OrthancPlugin') and
-            node.spelling.endswith('_t') and
-            node.spelling != '_OrthancPluginContext_t'):
-            name = node.spelling[len('_') : -len('_t')]
-            classes[name] = {
-                'class_name' : name,
-                'short_name' : name[len('OrthancPlugin'):],
-                'methods' : [ ],
-                'custom_methods' : [ ],
-            }
-                    
-
-
-
-partials = {}
-
-with open(os.path.join(ROOT, 'FunctionBody.mustache'), 'r') as f:
-    partials['function_body'] = f.read()
-
-renderer = pystache.Renderer(
-    escape = lambda u: u,  # No escaping
-    partials = partials,
-)
-
-with open(os.path.join(ROOT, 'Class.mustache'), 'r') as f:
-    with open(os.path.join(ROOT, 'ClassMethods.mustache'), 'r') as g:
-        classDefinition = f.read()
-        classMethods = g.read()
-
-        for method in CUSTOM_METHODS:
-            classes[method['class_name']]['custom_methods'].append(method)
-
-        for (key, value) in classes.items():
-            with open(os.path.join(TARGET, 'sdk_%s.impl.h' % value['class_name']), 'w') as h:
-                h.write(renderer.render(classDefinition, value))
-            with open(os.path.join(TARGET, 'sdk_%s.methods.h' % value['class_name']), 'w') as h:
-                h.write(renderer.render(classMethods, value))
-        
-
-def FlattenDictionary(source):
-    result = []
-    for (key, value) in source.items():
-        result.append(value)
-    return result
-
-
-sortedClasses = sorted(FlattenDictionary(classes), key = lambda x: x['class_name'])
-sortedEnumerations = sorted(FlattenDictionary(enumerations), key = lambda x: x['name'])
-sortedGlobalFunctions = sorted(globalFunctions, key = lambda x: x['c_function'])
-
-with open(os.path.join(ROOT, 'GlobalFunctions.mustache'), 'r') as f:
-    with open(os.path.join(TARGET, 'sdk_GlobalFunctions.impl.h'), 'w') as h:
-        h.write(renderer.render(f.read(), {
-            'global_functions' : sortedGlobalFunctions,
-        }))
-            
-with open(os.path.join(ROOT, 'sdk.cpp.mustache'), 'r') as f:
-    with open(os.path.join(TARGET, 'sdk.cpp'), 'w') as h:
-        h.write(renderer.render(f.read(), {
-            'classes' : sortedClasses,
-            'enumerations' : sortedEnumerations,
-            'global_functions' : sortedGlobalFunctions,
-        }))
-            
-with open(os.path.join(ROOT, 'sdk.h.mustache'), 'r') as f:
-    with open(os.path.join(TARGET, 'sdk.h'), 'w') as h:
-        h.write(renderer.render(f.read(), {
-            'classes' : sortedClasses,
-        }))
-
-
-print('')
-print('Total functions in the SDK: %d' % countAllFunctions)
-print('Total supported functions: %d' % countSupportedFunctions)
-print('Coverage: %.0f%%' % (float(countSupportedFunctions) /
-                            float(countAllFunctions) * 100.0))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CodeAnalysis/PythonDocumentation.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,67 @@
+##
+## Python plugin for Orthanc
+## Copyright (C) 2020-2023 Osimis S.A., Belgium
+## Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+## Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+##
+## This program is free software: you can redistribute it and/or
+## modify it under the terms of the GNU Affero 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
+## Affero General Public License for more details.
+##
+## You should have received a copy of the GNU Affero General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+
+# WARNING: Auto-generated file. Do not modify it by hand.
+
+
+import enum
+import typing
+
+
+{{#enumerations}}
+
+class {{short_name}}(enum.Enum):
+    """
+    {{documentation}}
+    """
+{{#values}}
+
+    """
+    {{documentation}}
+    """
+    {{key}}: int = {{value}},
+{{/values}}
+{{/enumerations}}
+
+
+{{#global_functions}}
+{{> function_documentation}}
+{{/global_functions}}
+{{#custom_functions}}
+{{> function_documentation}}
+{{/custom_functions}}
+
+
+{{#classes}}
+class {{short_name}}:
+    """
+    {{description}}
+    """
+    ...
+
+{{#methods}}
+    {{> function_documentation}}
+{{/methods}}
+
+{{#custom_methods}}
+    {{> function_documentation}}
+{{/custom_methods}}
+{{/classes}}
--- a/CodeAnalysis/README.txt	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/README.txt	Tue Jul 02 19:06:54 2024 +0200
@@ -2,40 +2,14 @@
 Introduction
 ============
 
-This folder contains the Python script that analyzes the header of the
-Orthanc Plugin SDK using clang, then automatically wraps this SDK as a
-Python extension module. The output of the script is written to
-"../Sources/Autogenerated".
-
-
-Usage on Ubuntu 18.04
-=====================
+This folder contains the Python script that reads the code model of
+the Orthanc SDK that is generated by the "orthanc-java" project [1],
+then automatically wraps this SDK as a Python extension module.
 
-$ sudo apt-get install python-clang-4.0 python-pystache
-$ python2 ./ParseOrthancSDK.py --libclang=libclang-4.0.so.1 \
-          --source ../Resources/Orthanc/Sdk-1.10.0/orthanc/OrthancCPlugin.h \
-          --target ../Sources/Autogenerated
-
-
-Usage on Ubuntu 20.04
-=====================
+The output of the script is written to "../Sources/Autogenerated".
 
-$ sudo apt-get install python-clang-6.0 python3-pystache
-$ python3 ./ParseOrthancSDK.py --libclang=libclang-6.0.so.1 \
-          --source ../Resources/Orthanc/Sdk-1.10.0/orthanc/OrthancCPlugin.h \
-          --target ../Sources/Autogenerated
-
-
-Usage on Ubuntu 22.04
-=====================
+Usage:
 
-$ sudo apt-get install python3-clang-14 python3-pystache
-$ python3 ./ParseOrthancSDK.py --libclang=libclang-14.so.1 \
-          --source ../Resources/Orthanc/Sdk-1.10.0/orthanc/OrthancCPlugin.h \
-          --target ../Sources/Autogenerated
+$ ./GenerateOrthancSDK.py
 
-
-Run through docker
-==================
-
-$ docker-compose up --build
+[1] https://orthanc.uclouvain.be/book/plugins/java.html
--- a/CodeAnalysis/docker-compose.yml	Tue Jul 02 17:17:24 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-version: "3"
-
-services:
-  orthanc-sdk-parser:
-    build: .
-    volumes:
-      - ../Sources/Autogenerated:/target
-      - ../Resources/Orthanc/Sdk-1.10.0/orthanc/:/source
-      # to parse your local mainline orthanc, use the below line instead
-      # - /home/alain/o/orthanc/OrthancServer/Plugins/Include/orthanc/:/source
--- a/CodeAnalysis/sdk.cpp.mustache	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/sdk.cpp.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -19,9 +19,13 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 #include "sdk.h"
 
 #include "../PythonLock.h"
+#include "../PythonThreadsAllower.h"
 
 #include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
 
--- a/CodeAnalysis/sdk.h.mustache	Tue Jul 02 17:17:24 2024 +0200
+++ b/CodeAnalysis/sdk.h.mustache	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 #pragma once
 
 #include "../PythonHeaderWrapper.h"
--- a/NEWS	Tue Jul 02 17:17:24 2024 +0200
+++ b/NEWS	Tue Jul 02 19:06:54 2024 +0200
@@ -1,6 +1,9 @@
 Pending changes in the mainline
 ===============================
 
+* Created Python documentation for the Orthanc interface, check out "orthanc.pyi"
+* Added possibility to release the GIL during the call to the native SDK functions
+* Code model is now generated by the "orthanc-java" project
 * Added Windows builder for Python 3.12
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Sdk-1.10.0/ClassDocumentation.json	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,15 @@
+{
+  "OrthancPluginDicomInstance" : "DICOM instance managed by the Orthanc core",
+  "OrthancPluginDicomWebNode" : "Node visited by DICOMweb conversion",
+  "OrthancPluginFindAnswers" : "Answers to a DICOM C-FIND query",
+  "OrthancPluginFindMatcher" : "Matcher for DICOM C-FIND query",
+  "OrthancPluginFindQuery" : "DICOM C-FIND query",
+  "OrthancPluginImage" : "2D image managed by the Orthanc core",
+  "OrthancPluginJob" : "Orthanc job",
+  "OrthancPluginPeers" : "Orthanc peer",
+  "OrthancPluginRestOutput" : "Output for a call to the REST API of Orthanc",
+  "OrthancPluginServerChunkedRequestReader" : "Read for a chunked HTTP request",
+  "OrthancPluginStorageArea" : "Storage area plugin",
+  "OrthancPluginWorklistAnswers" : "Answers to a DICOM C-FIND worklist query",
+  "OrthancPluginWorklistQuery" : "DICOM C-FIND worklist query"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Sdk-1.10.0/ClassDocumentation.json.license	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,2 @@
+# SPDX-FileCopyrightText: 2023-2024 Sebastien Jodogne, UCLouvain, Belgium
+# SPDX-License-Identifier: GPL-3.0-or-later
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Sdk-1.10.0/CodeModel.json	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,4317 @@
+{
+    "classes": [
+        {
+            "destructor": "OrthancPluginFreeDicomInstance",
+            "methods": [
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceRemoteAet",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the Application Entity Title (AET) of the DICOM modality from which a DICOM instance originates."
+                        ],
+                        "return": "The AET if success, NULL if error.",
+                        "summary": "Get the AET of a DICOM instance."
+                    },
+                    "return_sdk_type": "const char *"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceSize",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the number of bytes of the given DICOM instance."
+                        ],
+                        "return": "The size of the file, -1 in case of error.",
+                        "summary": "Get the size of a DICOM file."
+                    },
+                    "return_sdk_type": "int64_t"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceJson",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns a pointer to a newly created string containing a JSON file. This JSON file encodes the tag hierarchy of the given DICOM instance."
+                        ],
+                        "return": "The NULL value in case of error, or a string containing the JSON file. This string must be freed by OrthancPluginFreeString().",
+                        "summary": "Get the DICOM tag hierarchy as a JSON file."
+                    },
+                    "return_sdk_type": "char *"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceSimplifiedJson",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns a pointer to a newly created string containing a JSON file. This JSON file encodes the tag hierarchy of the given DICOM instance. In contrast with ::OrthancPluginGetInstanceJson(), the returned JSON file is in its simplified version."
+                        ],
+                        "return": "The NULL value in case of error, or a string containing the JSON file. This string must be freed by OrthancPluginFreeString().",
+                        "summary": "Get the DICOM tag hierarchy as a JSON file (with simplification)."
+                    },
+                    "return_sdk_type": "char *"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "metadata",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginHasInstanceMetadata",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "metadata": "The metadata of interest."
+                        },
+                        "description": [
+                            "This function checks whether the DICOM instance of interest is associated with some metadata. As of Orthanc 0.8.1, in the callbacks registered by ::OrthancPluginRegisterOnStoredInstanceCallback(), the only possibly available metadata are \"ReceptionDate\", \"RemoteAET\" and \"IndexInSeries\"."
+                        ],
+                        "return": "1 if the metadata is present, 0 if it is absent, -1 in case of error.",
+                        "summary": "Check whether a DICOM instance is associated with some metadata."
+                    },
+                    "return_sdk_type": "int32_t"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "metadata",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetInstanceMetadata",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "metadata": "The metadata of interest."
+                        },
+                        "description": [
+                            "This functions returns the value of some metadata that is associated with the DICOM instance of interest. Before calling this function, the existence of the metadata must have been checked with ::OrthancPluginHasInstanceMetadata()."
+                        ],
+                        "return": "The metadata value if success, NULL if error. Please note that the returned string belongs to the instance object and must NOT be deallocated. Please make a copy of the string if you wish to access it later.",
+                        "summary": "Get the value of some metadata associated with a given DICOM instance."
+                    },
+                    "return_sdk_type": "const char *"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceOrigin",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the origin of a DICOM instance that has been received by Orthanc."
+                        ],
+                        "return": "The origin of the instance.",
+                        "summary": "Get the origin of a DICOM file."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginInstanceOrigin",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceTransferSyntaxUid",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns a pointer to a newly created string that contains the transfer syntax UID of the DICOM instance. The empty string might be returned if this information is unknown."
+                        ],
+                        "return": "The NULL value in case of error, or a string containing the transfer syntax UID. This string must be freed by OrthancPluginFreeString().",
+                        "summary": "Get the transfer syntax of a DICOM file."
+                    },
+                    "return_sdk_type": "char *"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginHasInstancePixelData",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns a Boolean value indicating whether the DICOM instance contains the pixel data (7FE0,0010) tag."
+                        ],
+                        "return": "\"1\" if the DICOM instance contains pixel data, or \"0\" if the tag is missing, or \"-1\" in the case of an error.",
+                        "summary": "Check whether the DICOM file has pixel data."
+                    },
+                    "return_sdk_type": "int32_t"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetInstanceFramesCount",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the number of frames that are part of a DICOM image managed by the Orthanc core."
+                        ],
+                        "return": "The number of frames (will be zero in the case of an error).",
+                        "summary": "Get the number of frames in a DICOM instance."
+                    },
+                    "return_sdk_type": "uint32_t"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "frameIndex",
+                            "sdk_type": "uint32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetInstanceRawFrame",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "frameIndex": "The index of the frame of interest.",
+                            "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer()."
+                        },
+                        "description": [
+                            "This function returns a memory buffer containing the raw content of a frame in a DICOM instance that is managed by the Orthanc core. This is notably useful for compressed transfer syntaxes, as it gives access to the embedded files (such as JPEG, JPEG-LS or JPEG2k). The Orthanc core transparently reassembles the fragments to extract the raw frame."
+                        ],
+                        "return": "0 if success, or the error code if failure.",
+                        "summary": "Get the raw content of a frame in a DICOM instance."
+                    },
+                    "return_sdk_type": "OrthancPluginMemoryBuffer *"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "frameIndex",
+                            "sdk_type": "uint32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetInstanceDecodedFrame",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "frameIndex": "The index of the frame of interest."
+                        },
+                        "description": [
+                            "This function decodes one frame of a DICOM image that is managed by the Orthanc core."
+                        ],
+                        "return": "The uncompressed image. It must be freed with OrthancPluginFreeImage().",
+                        "summary": "Decode one frame from a DICOM instance."
+                    },
+                    "return_sdk_class": "OrthancPluginImage",
+                    "return_sdk_type": "object"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginSerializeDicomInstance",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer()."
+                        },
+                        "description": [
+                            "This function returns a memory buffer containing the serialization of a DICOM instance that is managed by the Orthanc core."
+                        ],
+                        "return": "0 if success, or the error code if failure.",
+                        "summary": "Writes a DICOM instance to a memory buffer."
+                    },
+                    "return_sdk_type": "OrthancPluginMemoryBuffer *"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_enumeration": "OrthancPluginDicomToJsonFormat",
+                            "sdk_name": "format",
+                            "sdk_type": "enumeration"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_enumeration": "OrthancPluginDicomToJsonFlags",
+                            "sdk_name": "flags",
+                            "sdk_type": "enumeration"
+                        },
+                        {
+                            "name": "arg2",
+                            "sdk_name": "maxStringLength",
+                            "sdk_type": "uint32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetInstanceAdvancedJson",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "flags": "Flags governing the output.",
+                            "format": "The output format.",
+                            "maxStringLength": "The maximum length of a field. Too long fields will be output as \"null\". The 0 value means no maximum length."
+                        },
+                        "description": [
+                            "This function takes as DICOM instance managed by the Orthanc core, and outputs a JSON string representing the tags of this DICOM file."
+                        ],
+                        "return": "The NULL value if the case of an error, or the JSON string. This string must be freed by OrthancPluginFreeString().",
+                        "summary": "Format a DICOM memory buffer as a JSON string."
+                    },
+                    "return_sdk_type": "char *"
+                }
+            ],
+            "name": "OrthancPluginDicomInstance"
+        },
+        {
+            "methods": [],
+            "name": "OrthancPluginDicomWebNode"
+        },
+        {
+            "methods": [
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "dicom",
+                            "sdk_type": "const_void_pointer_with_size"
+                        }
+                    ],
+                    "c_function": "OrthancPluginFindAddAnswer",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "dicom": "The answer to be added, encoded as a DICOM file.",
+                            "size": "The size of the DICOM file."
+                        },
+                        "description": [
+                            "This function adds one answer (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request that is not related to modality worklists."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Add one answer to some C-Find request."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginFindMarkIncomplete",
+                    "const": false,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function marks as incomplete the set of answers corresponding to some C-Find SCP request that is not related to modality worklists. This must be used if canceling the handling of a request when too many answers are to be returned."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Mark the set of C-Find answers as incomplete."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                }
+            ],
+            "name": "OrthancPluginFindAnswers"
+        },
+        {
+            "destructor": "OrthancPluginFreeFindMatcher",
+            "methods": [
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "dicom",
+                            "sdk_type": "const_void_pointer_with_size"
+                        }
+                    ],
+                    "c_function": "OrthancPluginFindMatcherIsMatch",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "dicom": "The DICOM instance to be matched.",
+                            "size": "The size of the DICOM instance."
+                        },
+                        "description": [
+                            "This function checks whether one DICOM instance matches C-Find matcher that was previously allocated using OrthancPluginCreateFindMatcher()."
+                        ],
+                        "return": "1 if the DICOM instance matches the query, 0 otherwise.",
+                        "summary": "Test whether a DICOM instance matches a C-Find query."
+                    },
+                    "return_sdk_type": "int32_t"
+                }
+            ],
+            "name": "OrthancPluginFindMatcher"
+        },
+        {
+            "methods": [
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetFindQuerySize",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the number of tags that are contained in the given C-Find query."
+                        ],
+                        "return": "The number of tags.",
+                        "summary": "Get the number of tags in a C-Find query."
+                    },
+                    "return_sdk_type": "uint32_t"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "index",
+                            "sdk_type": "uint32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetFindQueryTagName",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "index": "The index of the tag of interest."
+                        },
+                        "description": [
+                            "This function returns the symbolic name of one DICOM tag in the given C-Find query."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Get the symbolic name of one tag in a C-Find query."
+                    },
+                    "return_sdk_type": "char *"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "index",
+                            "sdk_type": "uint32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetFindQueryValue",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "index": "The index of the tag of interest."
+                        },
+                        "description": [
+                            "This function returns the value associated with one tag in the given C-Find query."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Get the value associated with one tag in a C-Find query."
+                    },
+                    "return_sdk_type": "char *"
+                }
+            ],
+            "name": "OrthancPluginFindQuery"
+        },
+        {
+            "destructor": "OrthancPluginFreeImage",
+            "methods": [
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetImagePixelFormat",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the type of memory layout for the pixels of the given image."
+                        ],
+                        "return": "The pixel format.",
+                        "summary": "Return the pixel format of an image."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginPixelFormat",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetImageWidth",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the width of the given image."
+                        ],
+                        "return": "The width.",
+                        "summary": "Return the width of an image."
+                    },
+                    "return_sdk_type": "uint32_t"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetImageHeight",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the height of the given image."
+                        ],
+                        "return": "The height.",
+                        "summary": "Return the height of an image."
+                    },
+                    "return_sdk_type": "uint32_t"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetImagePitch",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the pitch of the given image. The pitch is defined as the number of bytes between 2 successive lines of the image in the memory buffer."
+                        ],
+                        "return": "The pitch.",
+                        "summary": "Return the pitch of an image."
+                    },
+                    "return_sdk_type": "uint32_t"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_enumeration": "OrthancPluginPixelFormat",
+                            "sdk_name": "targetFormat",
+                            "sdk_type": "enumeration"
+                        }
+                    ],
+                    "c_function": "OrthancPluginConvertPixelFormat",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "targetFormat": "The target pixel format."
+                        },
+                        "description": [
+                            "This function creates a new image, changing the memory layout of the pixels."
+                        ],
+                        "return": "The resulting image. It must be freed with OrthancPluginFreeImage().",
+                        "summary": "Change the pixel format of an image."
+                    },
+                    "return_sdk_class": "OrthancPluginImage",
+                    "return_sdk_type": "object"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "fontIndex",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "utf8Text",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg2",
+                            "sdk_name": "x",
+                            "sdk_type": "int32_t"
+                        },
+                        {
+                            "name": "arg3",
+                            "sdk_name": "y",
+                            "sdk_type": "int32_t"
+                        },
+                        {
+                            "name": "arg4",
+                            "sdk_name": "r",
+                            "sdk_type": "uint8_t"
+                        },
+                        {
+                            "name": "arg5",
+                            "sdk_name": "g",
+                            "sdk_type": "uint8_t"
+                        },
+                        {
+                            "name": "arg6",
+                            "sdk_name": "b",
+                            "sdk_type": "uint8_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginDrawText",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "b": "The value of the blue color channel of the text.",
+                            "fontIndex": "The index of the font. This value must be less than OrthancPluginGetFontsCount().",
+                            "g": "The value of the green color channel of the text.",
+                            "r": "The value of the red color channel of the text.",
+                            "utf8Text": "The text to be drawn, encoded as an UTF-8 zero-terminated string.",
+                            "x": "The X position of the text over the image.",
+                            "y": "The Y position of the text over the image."
+                        },
+                        "description": [
+                            "This function draws some text on some image."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Draw text on an image."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                }
+            ],
+            "name": "OrthancPluginImage"
+        },
+        {
+            "destructor": "OrthancPluginFreeJob",
+            "methods": [
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "priority",
+                            "sdk_type": "int32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSubmitJob",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "priority": "The priority of the job."
+                        },
+                        "description": [
+                            "This function adds the given job to the pending jobs of Orthanc. Orthanc will take take of freeing it by invoking the finalization callback provided to OrthancPluginCreateJob()."
+                        ],
+                        "return": "ID of the newly-submitted job. This string must be freed by OrthancPluginFreeString().",
+                        "summary": "Submit a new job to the jobs engine of Orthanc."
+                    },
+                    "return_sdk_type": "char *"
+                }
+            ],
+            "name": "OrthancPluginJob"
+        },
+        {
+            "destructor": "OrthancPluginFreePeers",
+            "methods": [
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginGetPeersCount",
+                    "const": true,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function returns the number of Orthanc peers.",
+                            "This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function."
+                        ],
+                        "return": "The number of peers.",
+                        "summary": "Get the number of Orthanc peers."
+                    },
+                    "return_sdk_type": "uint32_t"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "peerIndex",
+                            "sdk_type": "uint32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetPeerName",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "peerIndex": "The index of the peer of interest. This value must be lower than OrthancPluginGetPeersCount()."
+                        },
+                        "description": [
+                            "This function returns the symbolic name of the Orthanc peer, which corresponds to the key of the \"OrthancPeers\" configuration option of Orthanc.",
+                            "This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function."
+                        ],
+                        "return": "The symbolic name, or NULL in the case of an error.",
+                        "summary": "Get the symbolic name of an Orthanc peer."
+                    },
+                    "return_sdk_type": "const char *"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "peerIndex",
+                            "sdk_type": "uint32_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetPeerUrl",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "peerIndex": "The index of the peer of interest. This value must be lower than OrthancPluginGetPeersCount()."
+                        },
+                        "description": [
+                            "This function returns the base URL to the REST API of some Orthanc peer.",
+                            "This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function."
+                        ],
+                        "return": "The URL, or NULL in the case of an error.",
+                        "summary": "Get the base URL of an Orthanc peer."
+                    },
+                    "return_sdk_type": "const char *"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "peerIndex",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "userProperty",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginGetPeerUserProperty",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "peerIndex": "The index of the peer of interest. This value must be lower than OrthancPluginGetPeersCount().",
+                            "userProperty": "The user property of interest."
+                        },
+                        "description": [
+                            "This function returns some user-defined property of some Orthanc peer. An user-defined property is a property that is associated with the peer in the Orthanc configuration file, but that is not recognized by the Orthanc core.",
+                            "This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function."
+                        ],
+                        "return": "The value of the user property, or NULL if it is not defined.",
+                        "summary": "Get some user-defined property of an Orthanc peer."
+                    },
+                    "return_sdk_type": "const char *"
+                }
+            ],
+            "name": "OrthancPluginPeers"
+        },
+        {
+            "methods": [
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "answer",
+                            "sdk_type": "const_void_pointer_with_size"
+                        },
+                        {
+                            "name": "arg2",
+                            "sdk_name": "mimeType",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginAnswerBuffer",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "answer": "Pointer to the memory buffer containing the answer.",
+                            "answerSize": "Number of bytes of the answer.",
+                            "mimeType": "The MIME type of the answer."
+                        },
+                        "description": [
+                            "This function answers to a REST request with the content of a memory buffer."
+                        ],
+                        "summary": "Answer to a REST request."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_enumeration": "OrthancPluginPixelFormat",
+                            "sdk_name": "format",
+                            "sdk_type": "enumeration"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "width",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg2",
+                            "sdk_name": "height",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg3",
+                            "sdk_name": "pitch",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg4",
+                            "sdk_name": "buffer",
+                            "sdk_type": "const void *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginCompressAndAnswerPngImage",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "buffer": "The memory buffer containing the uncompressed image.",
+                            "format": "The memory layout of the uncompressed image.",
+                            "height": "The height of the image.",
+                            "pitch": "The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).",
+                            "width": "The width of the image."
+                        },
+                        "description": [
+                            "This function answers to a REST request with a PNG image. The parameters of this function describe a memory buffer that contains an uncompressed image. The image will be automatically compressed as a PNG image by the core system of Orthanc."
+                        ],
+                        "summary": "Answer to a REST request with a PNG image."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "redirection",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginRedirect",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "redirection": "Where to redirect."
+                        },
+                        "description": [
+                            "This function answers to a REST request by redirecting the user to another URI using HTTP status 301."
+                        ],
+                        "summary": "Redirect a REST request."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "status",
+                            "sdk_type": "uint16_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSendHttpStatusCode",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "status": "The HTTP status code to be sent."
+                        },
+                        "description": [
+                            "This function answers to a REST request by sending a HTTP status code (such as \"400 - Bad Request\"). Note that: - Successful requests (status 200) must use ::OrthancPluginAnswerBuffer(). - Redirections (status 301) must use ::OrthancPluginRedirect(). - Unauthorized access (status 401) must use ::OrthancPluginSendUnauthorized(). - Methods not allowed (status 405) must use ::OrthancPluginSendMethodNotAllowed()."
+                        ],
+                        "summary": "Send a HTTP status code."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "realm",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSendUnauthorized",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "realm": "The realm for the authorization process."
+                        },
+                        "description": [
+                            "This function answers to a REST request by signaling that it is not authorized."
+                        ],
+                        "summary": "Signal that a REST request is not authorized."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "allowedMethods",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSendMethodNotAllowed",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "allowedMethods": "The allowed methods for this URI (e.g. \"GET,POST\" after a PUT or a POST request)."
+                        },
+                        "description": [
+                            "This function answers to a REST request by signaling that the queried URI does not support this method."
+                        ],
+                        "summary": "Signal that this URI does not support this HTTP method."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "cookie",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "value",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSetCookie",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "cookie": "The cookie to be set.",
+                            "value": "The value of the cookie."
+                        },
+                        "description": [
+                            "This function sets a cookie in the HTTP client."
+                        ],
+                        "summary": "Set a cookie."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "key",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "value",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSetHttpHeader",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "key": "The HTTP header to be set.",
+                            "value": "The value of the HTTP header."
+                        },
+                        "description": [
+                            "This function sets a HTTP header in the HTTP answer."
+                        ],
+                        "summary": "Set some HTTP header."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "subType",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "contentType",
+                            "sdk_type": "const char *"
+                        }
+                    ],
+                    "c_function": "OrthancPluginStartMultipartAnswer",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "contentType": "The MIME type of the items in the multipart answer.",
+                            "subType": "The sub-type of the multipart answer (\"mixed\" or \"related\")."
+                        },
+                        "description": [
+                            "Initiates a HTTP multipart answer, as the result of a REST request."
+                        ],
+                        "return": "0 if success, or the error code if failure.",
+                        "summary": "Start an HTTP multipart answer."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "answer",
+                            "sdk_type": "const_void_pointer_with_size"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSendMultipartItem",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "answer": "Pointer to the memory buffer containing the item.",
+                            "answerSize": "Number of bytes of the item."
+                        },
+                        "description": [
+                            "This function sends an item as a part of some HTTP multipart answer that was initiated by OrthancPluginStartMultipartAnswer()."
+                        ],
+                        "return": "0 if success, or the error code if failure (this notably happens if the connection is closed by the client).",
+                        "summary": "Send an item as a part of some HTTP multipart answer."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "status",
+                            "sdk_type": "uint16_t"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "body",
+                            "sdk_type": "const_void_pointer_with_size"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSendHttpStatus",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "body": "The body of the answer.",
+                            "bodySize": "The size of the body.",
+                            "status": "The HTTP status code to be sent."
+                        },
+                        "description": [
+                            "This function answers to a HTTP request by sending a HTTP status code (such as \"400 - Bad Request\"), together with a body describing the error. The body will only be returned if the configuration option \"HttpDescribeErrors\" of Orthanc is set to \"true\".",
+                            "Note that: - Successful requests (status 200) must use ::OrthancPluginAnswerBuffer(). - Redirections (status 301) must use ::OrthancPluginRedirect(). - Unauthorized access (status 401) must use ::OrthancPluginSendUnauthorized(). - Methods not allowed (status 405) must use ::OrthancPluginSendMethodNotAllowed()."
+                        ],
+                        "summary": "Send a HTTP status, with a custom body."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_enumeration": "OrthancPluginPixelFormat",
+                            "sdk_name": "format",
+                            "sdk_type": "enumeration"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "width",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg2",
+                            "sdk_name": "height",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg3",
+                            "sdk_name": "pitch",
+                            "sdk_type": "uint32_t"
+                        },
+                        {
+                            "name": "arg4",
+                            "sdk_name": "buffer",
+                            "sdk_type": "const void *"
+                        },
+                        {
+                            "name": "arg5",
+                            "sdk_name": "quality",
+                            "sdk_type": "uint8_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginCompressAndAnswerJpegImage",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "buffer": "The memory buffer containing the uncompressed image.",
+                            "format": "The memory layout of the uncompressed image.",
+                            "height": "The height of the image.",
+                            "pitch": "The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).",
+                            "quality": "The quality of the JPEG encoding, between 1 (worst quality, best compression) and 100 (best quality, worst compression).",
+                            "width": "The width of the image."
+                        },
+                        "description": [
+                            "This function answers to a REST request with a JPEG image. The parameters of this function describe a memory buffer that contains an uncompressed image. The image will be automatically compressed as a JPEG image by the core system of Orthanc."
+                        ],
+                        "summary": "Answer to a REST request with a JPEG image."
+                    },
+                    "return_sdk_type": "void"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "details",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "log",
+                            "sdk_type": "uint8_t"
+                        }
+                    ],
+                    "c_function": "OrthancPluginSetHttpErrorDetails",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "details": "The details of the error message.",
+                            "log": "Whether to also write the detailed error to the Orthanc logs."
+                        },
+                        "description": [
+                            "This function sets the detailed description associated with an HTTP error. This description will be displayed in the \"Details\" field of the JSON body of the HTTP answer. It is only taken into consideration if the REST callback returns an error code that is different from \"OrthancPluginErrorCode_Success\", and if the \"HttpDescribeErrors\" configuration option of Orthanc is set to \"true\"."
+                        ],
+                        "summary": "Provide a detailed description for an HTTP error."
+                    },
+                    "return_sdk_type": "void"
+                }
+            ],
+            "name": "OrthancPluginRestOutput"
+        },
+        {
+            "methods": [],
+            "name": "OrthancPluginServerChunkedRequestReader"
+        },
+        {
+            "methods": [
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "uuid",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "content",
+                            "sdk_type": "const void *"
+                        },
+                        {
+                            "name": "arg2",
+                            "sdk_name": "size",
+                            "sdk_type": "uint64_t"
+                        },
+                        {
+                            "name": "arg3",
+                            "sdk_enumeration": "OrthancPluginContentType",
+                            "sdk_name": "type",
+                            "sdk_type": "enumeration"
+                        }
+                    ],
+                    "c_function": "OrthancPluginStorageAreaCreate",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "content": "The content to store in the newly created file.",
+                            "size": "The size of the content.",
+                            "type": "The type of the file content.",
+                            "uuid": "The identifier of the file to be created."
+                        },
+                        "description": [
+                            "This function creates a new file inside the storage area that is currently used by Orthanc."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Create a file inside the storage area."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "uuid",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_enumeration": "OrthancPluginContentType",
+                            "sdk_name": "type",
+                            "sdk_type": "enumeration"
+                        }
+                    ],
+                    "c_function": "OrthancPluginStorageAreaRead",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                            "type": "The type of the file content.",
+                            "uuid": "The identifier of the file to be read."
+                        },
+                        "description": [
+                            "This function reads the content of a given file from the storage area that is currently used by Orthanc."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Read a file from the storage area."
+                    },
+                    "return_sdk_type": "OrthancPluginMemoryBuffer *"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "uuid",
+                            "sdk_type": "const char *"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_enumeration": "OrthancPluginContentType",
+                            "sdk_name": "type",
+                            "sdk_type": "enumeration"
+                        }
+                    ],
+                    "c_function": "OrthancPluginStorageAreaRemove",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "type": "The type of the file content.",
+                            "uuid": "The identifier of the file to be removed."
+                        },
+                        "description": [
+                            "This function removes a given file from the storage area that is currently used by Orthanc."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Remove a file from the storage area."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_enumeration": "OrthancPluginResourceType",
+                            "sdk_name": "level",
+                            "sdk_type": "enumeration"
+                        }
+                    ],
+                    "c_function": "OrthancPluginReconstructMainDicomTags",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "level": "The type of the resources of interest."
+                        },
+                        "description": [
+                            "This function requests the Orthanc core to reconstruct the main DICOM tags of all the resources of the given type. This function can only be used as a part of the upgrade of a custom database back-end. A database transaction will be automatically setup."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Reconstruct the main DICOM tags."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                }
+            ],
+            "name": "OrthancPluginStorageArea"
+        },
+        {
+            "methods": [
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_class": "OrthancPluginWorklistQuery",
+                            "sdk_name": "query",
+                            "sdk_type": "const_object"
+                        },
+                        {
+                            "name": "arg1",
+                            "sdk_name": "dicom",
+                            "sdk_type": "const_void_pointer_with_size"
+                        }
+                    ],
+                    "c_function": "OrthancPluginWorklistAddAnswer",
+                    "const": false,
+                    "documentation": {
+                        "args": {
+                            "dicom": "The worklist to answer, encoded as a DICOM file.",
+                            "query": "The worklist query, as received by the callback.",
+                            "size": "The size of the DICOM file."
+                        },
+                        "description": [
+                            "This function adds one worklist (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request against modality worklists."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Add one answer to some modality worklist request."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginWorklistMarkIncomplete",
+                    "const": false,
+                    "documentation": {
+                        "args": {},
+                        "description": [
+                            "This function marks as incomplete the set of answers corresponding to some C-Find SCP request against modality worklists. This must be used if canceling the handling of a request when too many answers are to be returned."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Mark the set of worklist answers as incomplete."
+                    },
+                    "return_sdk_enumeration": "OrthancPluginErrorCode",
+                    "return_sdk_type": "enumeration"
+                }
+            ],
+            "name": "OrthancPluginWorklistAnswers"
+        },
+        {
+            "methods": [
+                {
+                    "args": [
+                        {
+                            "name": "arg0",
+                            "sdk_name": "dicom",
+                            "sdk_type": "const_void_pointer_with_size"
+                        }
+                    ],
+                    "c_function": "OrthancPluginWorklistIsMatch",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "dicom": "The worklist to answer, encoded as a DICOM file.",
+                            "size": "The size of the DICOM file."
+                        },
+                        "description": [
+                            "This function checks whether one worklist (encoded as a DICOM file) matches the C-Find SCP query against modality worklists. This function must be called before adding the worklist as an answer through OrthancPluginWorklistAddAnswer()."
+                        ],
+                        "return": "1 if the worklist matches the query, 0 otherwise.",
+                        "summary": "Test whether a worklist matches the query."
+                    },
+                    "return_sdk_type": "int32_t"
+                },
+                {
+                    "args": [],
+                    "c_function": "OrthancPluginWorklistGetDicomQuery",
+                    "const": true,
+                    "documentation": {
+                        "args": {
+                            "target": "Memory buffer where to store the DICOM file. It must be freed with OrthancPluginFreeMemoryBuffer()."
+                        },
+                        "description": [
+                            "This function retrieves the DICOM file that underlies a C-Find SCP query against modality worklists."
+                        ],
+                        "return": "0 if success, other value if error.",
+                        "summary": "Retrieve the worklist query as a DICOM file."
+                    },
+                    "return_sdk_type": "OrthancPluginMemoryBuffer *"
+                }
+            ],
+            "name": "OrthancPluginWorklistQuery"
+        }
+    ],
+    "enumerations": [
+        {
+            "documentation": "The supported types of changes that can be signaled to the change callback.",
+            "name": "OrthancPluginChangeType",
+            "values": [
+                {
+                    "documentation": "Series is now complete",
+                    "key": "CompletedSeries",
+                    "value": 0
+                },
+                {
+                    "documentation": "Deleted resource",
+                    "key": "Deleted",
+                    "value": 1
+                },
+                {
+                    "documentation": "A new instance was added to this resource",
+                    "key": "NewChildInstance",
+                    "value": 2
+                },
+                {
+                    "documentation": "New instance received",
+                    "key": "NewInstance",
+                    "value": 3
+                },
+                {
+                    "documentation": "New patient created",
+                    "key": "NewPatient",
+                    "value": 4
+                },
+                {
+                    "documentation": "New series created",
+                    "key": "NewSeries",
+                    "value": 5
+                },
+                {
+                    "documentation": "New study created",
+                    "key": "NewStudy",
+                    "value": 6
+                },
+                {
+                    "documentation": "Timeout: No new instance in this patient",
+                    "key": "StablePatient",
+                    "value": 7
+                },
+                {
+                    "documentation": "Timeout: No new instance in this series",
+                    "key": "StableSeries",
+                    "value": 8
+                },
+                {
+                    "documentation": "Timeout: No new instance in this study",
+                    "key": "StableStudy",
+                    "value": 9
+                },
+                {
+                    "documentation": "Orthanc has started",
+                    "key": "OrthancStarted",
+                    "value": 10
+                },
+                {
+                    "documentation": "Orthanc is stopping",
+                    "key": "OrthancStopped",
+                    "value": 11
+                },
+                {
+                    "documentation": "Some user-defined attachment has changed for this resource",
+                    "key": "UpdatedAttachment",
+                    "value": 12
+                },
+                {
+                    "documentation": "Some user-defined metadata has changed for this resource",
+                    "key": "UpdatedMetadata",
+                    "value": 13
+                },
+                {
+                    "documentation": "The list of Orthanc peers has changed",
+                    "key": "UpdatedPeers",
+                    "value": 14
+                },
+                {
+                    "documentation": "The list of DICOM modalities has changed",
+                    "key": "UpdatedModalities",
+                    "value": 15
+                },
+                {
+                    "documentation": "New Job submitted",
+                    "key": "JobSubmitted",
+                    "value": 16
+                },
+                {
+                    "documentation": "A Job has completed successfully",
+                    "key": "JobSuccess",
+                    "value": 17
+                },
+                {
+                    "documentation": "A Job has failed",
+                    "key": "JobFailure",
+                    "value": 18
+                }
+            ]
+        },
+        {
+            "documentation": "The compression algorithms that are supported by the Orthanc core.",
+            "name": "OrthancPluginCompressionType",
+            "values": [
+                {
+                    "documentation": "Standard zlib compression",
+                    "key": "Zlib",
+                    "value": 0
+                },
+                {
+                    "documentation": "zlib, prefixed with uncompressed size (uint64_t)",
+                    "key": "ZlibWithSize",
+                    "value": 1
+                },
+                {
+                    "documentation": "Standard gzip compression",
+                    "key": "Gzip",
+                    "value": 2
+                },
+                {
+                    "documentation": "gzip, prefixed with uncompressed size (uint64_t)",
+                    "key": "GzipWithSize",
+                    "value": 3
+                }
+            ]
+        },
+        {
+            "documentation": "The constraints on the tags (main DICOM tags and identifier tags) that must be supported by the database plugins.",
+            "name": "OrthancPluginConstraintType",
+            "values": [
+                {
+                    "documentation": "Equal",
+                    "key": "Equal",
+                    "value": 1
+                },
+                {
+                    "documentation": "Less or equal",
+                    "key": "SmallerOrEqual",
+                    "value": 2
+                },
+                {
+                    "documentation": "More or equal",
+                    "key": "GreaterOrEqual",
+                    "value": 3
+                },
+                {
+                    "documentation": "Wildcard matching",
+                    "key": "Wildcard",
+                    "value": 4
+                },
+                {
+                    "documentation": "List of values",
+                    "key": "List",
+                    "value": 5
+                }
+            ]
+        },
+        {
+            "documentation": "The content types that are supported by Orthanc plugins.",
+            "name": "OrthancPluginContentType",
+            "values": [
+                {
+                    "documentation": "Unknown content type",
+                    "key": "Unknown",
+                    "value": 0
+                },
+                {
+                    "documentation": "DICOM",
+                    "key": "Dicom",
+                    "value": 1
+                },
+                {
+                    "documentation": "JSON summary of a DICOM file",
+                    "key": "DicomAsJson",
+                    "value": 2
+                },
+                {
+                    "documentation": "DICOM Header till pixel data",
+                    "key": "DicomUntilPixelData",
+                    "value": 3
+                }
+            ]
+        },
+        {
+            "documentation": "Flags to the creation of a DICOM file.",
+            "name": "OrthancPluginCreateDicomFlags",
+            "values": [
+                {
+                    "documentation": "Default mode",
+                    "key": "None",
+                    "value": 0
+                },
+                {
+                    "documentation": "Decode fields encoded using data URI scheme",
+                    "key": "DecodeDataUriScheme",
+                    "value": 1
+                },
+                {
+                    "documentation": "Automatically generate DICOM identifiers",
+                    "key": "GenerateIdentifiers",
+                    "value": 2
+                }
+            ]
+        },
+        {
+            "documentation": "Flags to customize a DICOM-to-JSON conversion. By default, binary tags are formatted using Data URI scheme.",
+            "name": "OrthancPluginDicomToJsonFlags",
+            "values": [
+                {
+                    "documentation": "Default formatting",
+                    "key": "None",
+                    "value": 0
+                },
+                {
+                    "documentation": "Include the binary tags",
+                    "key": "IncludeBinary",
+                    "value": 1
+                },
+                {
+                    "documentation": "Include the private tags",
+                    "key": "IncludePrivateTags",
+                    "value": 2
+                },
+                {
+                    "documentation": "Include the tags unknown by the dictionary",
+                    "key": "IncludeUnknownTags",
+                    "value": 4
+                },
+                {
+                    "documentation": "Include the pixel data",
+                    "key": "IncludePixelData",
+                    "value": 8
+                },
+                {
+                    "documentation": "Output binary tags as-is, dropping non-ASCII",
+                    "key": "ConvertBinaryToAscii",
+                    "value": 16
+                },
+                {
+                    "documentation": "Signal binary tags as null values",
+                    "key": "ConvertBinaryToNull",
+                    "value": 32
+                },
+                {
+                    "documentation": "Stop processing after pixel data (new in 1.9.1)",
+                    "key": "StopAfterPixelData",
+                    "value": 64
+                },
+                {
+                    "documentation": "Skip tags whose element is zero (new in 1.9.1)",
+                    "key": "SkipGroupLengths",
+                    "value": 128
+                }
+            ]
+        },
+        {
+            "documentation": "The possible output formats for a DICOM-to-JSON conversion.",
+            "name": "OrthancPluginDicomToJsonFormat",
+            "values": [
+                {
+                    "documentation": "Full output, with most details",
+                    "key": "Full",
+                    "value": 1
+                },
+                {
+                    "documentation": "Tags output as hexadecimal numbers",
+                    "key": "Short",
+                    "value": 2
+                },
+                {
+                    "documentation": "Human-readable JSON",
+                    "key": "Human",
+                    "value": 3
+                }
+            ]
+        },
+        {
+            "documentation": "The available modes to export a binary DICOM tag into a DICOMweb JSON or XML document.",
+            "name": "OrthancPluginDicomWebBinaryMode",
+            "values": [
+                {
+                    "documentation": "Don't include binary tags",
+                    "key": "Ignore",
+                    "value": 0
+                },
+                {
+                    "documentation": "Inline encoding using Base64",
+                    "key": "InlineBinary",
+                    "value": 1
+                },
+                {
+                    "documentation": "Use a bulk data URI field",
+                    "key": "BulkDataUri",
+                    "value": 2
+                }
+            ]
+        },
+        {
+            "documentation": "The various error codes that can be returned by the Orthanc core.",
+            "name": "OrthancPluginErrorCode",
+            "values": [
+                {
+                    "documentation": "Internal error",
+                    "key": "InternalError",
+                    "value": -1
+                },
+                {
+                    "documentation": "Success",
+                    "key": "Success",
+                    "value": 0
+                },
+                {
+                    "documentation": "Error encountered within the plugin engine",
+                    "key": "Plugin",
+                    "value": 1
+                },
+                {
+                    "documentation": "Not implemented yet",
+                    "key": "NotImplemented",
+                    "value": 2
+                },
+                {
+                    "documentation": "Parameter out of range",
+                    "key": "ParameterOutOfRange",
+                    "value": 3
+                },
+                {
+                    "documentation": "The server hosting Orthanc is running out of memory",
+                    "key": "NotEnoughMemory",
+                    "value": 4
+                },
+                {
+                    "documentation": "Bad type for a parameter",
+                    "key": "BadParameterType",
+                    "value": 5
+                },
+                {
+                    "documentation": "Bad sequence of calls",
+                    "key": "BadSequenceOfCalls",
+                    "value": 6
+                },
+                {
+                    "documentation": "Accessing an inexistent item",
+                    "key": "InexistentItem",
+                    "value": 7
+                },
+                {
+                    "documentation": "Bad request",
+                    "key": "BadRequest",
+                    "value": 8
+                },
+                {
+                    "documentation": "Error in the network protocol",
+                    "key": "NetworkProtocol",
+                    "value": 9
+                },
+                {
+                    "documentation": "Error while calling a system command",
+                    "key": "SystemCommand",
+                    "value": 10
+                },
+                {
+                    "documentation": "Error with the database engine",
+                    "key": "Database",
+                    "value": 11
+                },
+                {
+                    "documentation": "Badly formatted URI",
+                    "key": "UriSyntax",
+                    "value": 12
+                },
+                {
+                    "documentation": "Inexistent file",
+                    "key": "InexistentFile",
+                    "value": 13
+                },
+                {
+                    "documentation": "Cannot write to file",
+                    "key": "CannotWriteFile",
+                    "value": 14
+                },
+                {
+                    "documentation": "Bad file format",
+                    "key": "BadFileFormat",
+                    "value": 15
+                },
+                {
+                    "documentation": "Timeout",
+                    "key": "Timeout",
+                    "value": 16
+                },
+                {
+                    "documentation": "Unknown resource",
+                    "key": "UnknownResource",
+                    "value": 17
+                },
+                {
+                    "documentation": "Incompatible version of the database",
+                    "key": "IncompatibleDatabaseVersion",
+                    "value": 18
+                },
+                {
+                    "documentation": "The file storage is full",
+                    "key": "FullStorage",
+                    "value": 19
+                },
+                {
+                    "documentation": "Corrupted file (e.g. inconsistent MD5 hash)",
+                    "key": "CorruptedFile",
+                    "value": 20
+                },
+                {
+                    "documentation": "Inexistent tag",
+                    "key": "InexistentTag",
+                    "value": 21
+                },
+                {
+                    "documentation": "Cannot modify a read-only data structure",
+                    "key": "ReadOnly",
+                    "value": 22
+                },
+                {
+                    "documentation": "Incompatible format of the images",
+                    "key": "IncompatibleImageFormat",
+                    "value": 23
+                },
+                {
+                    "documentation": "Incompatible size of the images",
+                    "key": "IncompatibleImageSize",
+                    "value": 24
+                },
+                {
+                    "documentation": "Error while using a shared library (plugin)",
+                    "key": "SharedLibrary",
+                    "value": 25
+                },
+                {
+                    "documentation": "Plugin invoking an unknown service",
+                    "key": "UnknownPluginService",
+                    "value": 26
+                },
+                {
+                    "documentation": "Unknown DICOM tag",
+                    "key": "UnknownDicomTag",
+                    "value": 27
+                },
+                {
+                    "documentation": "Cannot parse a JSON document",
+                    "key": "BadJson",
+                    "value": 28
+                },
+                {
+                    "documentation": "Bad credentials were provided to an HTTP request",
+                    "key": "Unauthorized",
+                    "value": 29
+                },
+                {
+                    "documentation": "Badly formatted font file",
+                    "key": "BadFont",
+                    "value": 30
+                },
+                {
+                    "documentation": "The plugin implementing a custom database back-end does not fulfill the proper interface",
+                    "key": "DatabasePlugin",
+                    "value": 31
+                },
+                {
+                    "documentation": "Error in the plugin implementing a custom storage area",
+                    "key": "StorageAreaPlugin",
+                    "value": 32
+                },
+                {
+                    "documentation": "The request is empty",
+                    "key": "EmptyRequest",
+                    "value": 33
+                },
+                {
+                    "documentation": "Cannot send a response which is acceptable according to the Accept HTTP header",
+                    "key": "NotAcceptable",
+                    "value": 34
+                },
+                {
+                    "documentation": "Cannot handle a NULL pointer",
+                    "key": "NullPointer",
+                    "value": 35
+                },
+                {
+                    "documentation": "The database is currently not available (probably a transient situation)",
+                    "key": "DatabaseUnavailable",
+                    "value": 36
+                },
+                {
+                    "documentation": "This job was canceled",
+                    "key": "CanceledJob",
+                    "value": 37
+                },
+                {
+                    "documentation": "Geometry error encountered in Stone",
+                    "key": "BadGeometry",
+                    "value": 38
+                },
+                {
+                    "documentation": "Cannot initialize SSL encryption, check out your certificates",
+                    "key": "SslInitialization",
+                    "value": 39
+                },
+                {
+                    "documentation": "Calling a function that has been removed from the Orthanc Framework",
+                    "key": "DiscontinuedAbi",
+                    "value": 40
+                },
+                {
+                    "documentation": "Incorrect range request",
+                    "key": "BadRange",
+                    "value": 41
+                },
+                {
+                    "documentation": "Database could not serialize access due to concurrent update, the transaction should be retried",
+                    "key": "DatabaseCannotSerialize",
+                    "value": 42
+                },
+                {
+                    "documentation": "A bad revision number was provided, which might indicate conflict between multiple writers",
+                    "key": "Revision",
+                    "value": 43
+                },
+                {
+                    "documentation": "SQLite: The database is not opened",
+                    "key": "SQLiteNotOpened",
+                    "value": 1000
+                },
+                {
+                    "documentation": "SQLite: Connection is already open",
+                    "key": "SQLiteAlreadyOpened",
+                    "value": 1001
+                },
+                {
+                    "documentation": "SQLite: Unable to open the database",
+                    "key": "SQLiteCannotOpen",
+                    "value": 1002
+                },
+                {
+                    "documentation": "SQLite: This cached statement is already being referred to",
+                    "key": "SQLiteStatementAlreadyUsed",
+                    "value": 1003
+                },
+                {
+                    "documentation": "SQLite: Cannot execute a command",
+                    "key": "SQLiteExecute",
+                    "value": 1004
+                },
+                {
+                    "documentation": "SQLite: Rolling back a nonexistent transaction (have you called Begin()?)",
+                    "key": "SQLiteRollbackWithoutTransaction",
+                    "value": 1005
+                },
+                {
+                    "documentation": "SQLite: Committing a nonexistent transaction",
+                    "key": "SQLiteCommitWithoutTransaction",
+                    "value": 1006
+                },
+                {
+                    "documentation": "SQLite: Unable to register a function",
+                    "key": "SQLiteRegisterFunction",
+                    "value": 1007
+                },
+                {
+                    "documentation": "SQLite: Unable to flush the database",
+                    "key": "SQLiteFlush",
+                    "value": 1008
+                },
+                {
+                    "documentation": "SQLite: Cannot run a cached statement",
+                    "key": "SQLiteCannotRun",
+                    "value": 1009
+                },
+                {
+                    "documentation": "SQLite: Cannot step over a cached statement",
+                    "key": "SQLiteCannotStep",
+                    "value": 1010
+                },
+                {
+                    "documentation": "SQLite: Bing a value while out of range (serious error)",
+                    "key": "SQLiteBindOutOfRange",
+                    "value": 1011
+                },
+                {
+                    "documentation": "SQLite: Cannot prepare a cached statement",
+                    "key": "SQLitePrepareStatement",
+                    "value": 1012
+                },
+                {
+                    "documentation": "SQLite: Beginning the same transaction twice",
+                    "key": "SQLiteTransactionAlreadyStarted",
+                    "value": 1013
+                },
+                {
+                    "documentation": "SQLite: Failure when committing the transaction",
+                    "key": "SQLiteTransactionCommit",
+                    "value": 1014
+                },
+                {
+                    "documentation": "SQLite: Cannot start a transaction",
+                    "key": "SQLiteTransactionBegin",
+                    "value": 1015
+                },
+                {
+                    "documentation": "The directory to be created is already occupied by a regular file",
+                    "key": "DirectoryOverFile",
+                    "value": 2000
+                },
+                {
+                    "documentation": "Unable to create a subdirectory or a file in the file storage",
+                    "key": "FileStorageCannotWrite",
+                    "value": 2001
+                },
+                {
+                    "documentation": "The specified path does not point to a directory",
+                    "key": "DirectoryExpected",
+                    "value": 2002
+                },
+                {
+                    "documentation": "The TCP port of the HTTP server is privileged or already in use",
+                    "key": "HttpPortInUse",
+                    "value": 2003
+                },
+                {
+                    "documentation": "The TCP port of the DICOM server is privileged or already in use",
+                    "key": "DicomPortInUse",
+                    "value": 2004
+                },
+                {
+                    "documentation": "This HTTP status is not allowed in a REST API",
+                    "key": "BadHttpStatusInRest",
+                    "value": 2005
+                },
+                {
+                    "documentation": "The specified path does not point to a regular file",
+                    "key": "RegularFileExpected",
+                    "value": 2006
+                },
+                {
+                    "documentation": "Unable to get the path to the executable",
+                    "key": "PathToExecutable",
+                    "value": 2007
+                },
+                {
+                    "documentation": "Cannot create a directory",
+                    "key": "MakeDirectory",
+                    "value": 2008
+                },
+                {
+                    "documentation": "An application entity title (AET) cannot be empty or be longer than 16 characters",
+                    "key": "BadApplicationEntityTitle",
+                    "value": 2009
+                },
+                {
+                    "documentation": "No request handler factory for DICOM C-FIND SCP",
+                    "key": "NoCFindHandler",
+                    "value": 2010
+                },
+                {
+                    "documentation": "No request handler factory for DICOM C-MOVE SCP",
+                    "key": "NoCMoveHandler",
+                    "value": 2011
+                },
+                {
+                    "documentation": "No request handler factory for DICOM C-STORE SCP",
+                    "key": "NoCStoreHandler",
+                    "value": 2012
+                },
+                {
+                    "documentation": "No application entity filter",
+                    "key": "NoApplicationEntityFilter",
+                    "value": 2013
+                },
+                {
+                    "documentation": "DicomUserConnection: Unable to find the SOP class and instance",
+                    "key": "NoSopClassOrInstance",
+                    "value": 2014
+                },
+                {
+                    "documentation": "DicomUserConnection: No acceptable presentation context for modality",
+                    "key": "NoPresentationContext",
+                    "value": 2015
+                },
+                {
+                    "documentation": "DicomUserConnection: The C-FIND command is not supported by the remote SCP",
+                    "key": "DicomFindUnavailable",
+                    "value": 2016
+                },
+                {
+                    "documentation": "DicomUserConnection: The C-MOVE command is not supported by the remote SCP",
+                    "key": "DicomMoveUnavailable",
+                    "value": 2017
+                },
+                {
+                    "documentation": "Cannot store an instance",
+                    "key": "CannotStoreInstance",
+                    "value": 2018
+                },
+                {
+                    "documentation": "Only string values are supported when creating DICOM instances",
+                    "key": "CreateDicomNotString",
+                    "value": 2019
+                },
+                {
+                    "documentation": "Trying to override a value inherited from a parent module",
+                    "key": "CreateDicomOverrideTag",
+                    "value": 2020
+                },
+                {
+                    "documentation": "Use \\\"Content\\\" to inject an image into a new DICOM instance",
+                    "key": "CreateDicomUseContent",
+                    "value": 2021
+                },
+                {
+                    "documentation": "No payload is present for one instance in the series",
+                    "key": "CreateDicomNoPayload",
+                    "value": 2022
+                },
+                {
+                    "documentation": "The payload of the DICOM instance must be specified according to Data URI scheme",
+                    "key": "CreateDicomUseDataUriScheme",
+                    "value": 2023
+                },
+                {
+                    "documentation": "Trying to attach a new DICOM instance to an inexistent resource",
+                    "key": "CreateDicomBadParent",
+                    "value": 2024
+                },
+                {
+                    "documentation": "Trying to attach a new DICOM instance to an instance (must be a series, study or patient)",
+                    "key": "CreateDicomParentIsInstance",
+                    "value": 2025
+                },
+                {
+                    "documentation": "Unable to get the encoding of the parent resource",
+                    "key": "CreateDicomParentEncoding",
+                    "value": 2026
+                },
+                {
+                    "documentation": "Unknown modality",
+                    "key": "UnknownModality",
+                    "value": 2027
+                },
+                {
+                    "documentation": "Bad ordering of filters in a job",
+                    "key": "BadJobOrdering",
+                    "value": 2028
+                },
+                {
+                    "documentation": "Cannot convert the given JSON object to a Lua table",
+                    "key": "JsonToLuaTable",
+                    "value": 2029
+                },
+                {
+                    "documentation": "Cannot create the Lua context",
+                    "key": "CannotCreateLua",
+                    "value": 2030
+                },
+                {
+                    "documentation": "Cannot execute a Lua command",
+                    "key": "CannotExecuteLua",
+                    "value": 2031
+                },
+                {
+                    "documentation": "Arguments cannot be pushed after the Lua function is executed",
+                    "key": "LuaAlreadyExecuted",
+                    "value": 2032
+                },
+                {
+                    "documentation": "The Lua function does not give the expected number of outputs",
+                    "key": "LuaBadOutput",
+                    "value": 2033
+                },
+                {
+                    "documentation": "The Lua function is not a predicate (only true/false outputs allowed)",
+                    "key": "NotLuaPredicate",
+                    "value": 2034
+                },
+                {
+                    "documentation": "The Lua function does not return a string",
+                    "key": "LuaReturnsNoString",
+                    "value": 2035
+                },
+                {
+                    "documentation": "Another plugin has already registered a custom storage area",
+                    "key": "StorageAreaAlreadyRegistered",
+                    "value": 2036
+                },
+                {
+                    "documentation": "Another plugin has already registered a custom database back-end",
+                    "key": "DatabaseBackendAlreadyRegistered",
+                    "value": 2037
+                },
+                {
+                    "documentation": "Plugin trying to call the database during its initialization",
+                    "key": "DatabaseNotInitialized",
+                    "value": 2038
+                },
+                {
+                    "documentation": "Orthanc has been built without SSL support",
+                    "key": "SslDisabled",
+                    "value": 2039
+                },
+                {
+                    "documentation": "Unable to order the slices of the series",
+                    "key": "CannotOrderSlices",
+                    "value": 2040
+                },
+                {
+                    "documentation": "No request handler factory for DICOM C-Find Modality SCP",
+                    "key": "NoWorklistHandler",
+                    "value": 2041
+                },
+                {
+                    "documentation": "Cannot override the value of a tag that already exists",
+                    "key": "AlreadyExistingTag",
+                    "value": 2042
+                },
+                {
+                    "documentation": "No request handler factory for DICOM N-ACTION SCP (storage commitment)",
+                    "key": "NoStorageCommitmentHandler",
+                    "value": 2043
+                },
+                {
+                    "documentation": "No request handler factory for DICOM C-GET SCP",
+                    "key": "NoCGetHandler",
+                    "value": 2044
+                },
+                {
+                    "documentation": "Unsupported media type",
+                    "key": "UnsupportedMediaType",
+                    "value": 3000
+                }
+            ]
+        },
+        {
+            "documentation": "The various HTTP methods for a REST call.",
+            "name": "OrthancPluginHttpMethod",
+            "values": [
+                {
+                    "documentation": "GET request",
+                    "key": "Get",
+                    "value": 1
+                },
+                {
+                    "documentation": "POST request",
+                    "key": "Post",
+                    "value": 2
+                },
+                {
+                    "documentation": "PUT request",
+                    "key": "Put",
+                    "value": 3
+                },
+                {
+                    "documentation": "DELETE request",
+                    "key": "Delete",
+                    "value": 4
+                }
+            ]
+        },
+        {
+            "documentation": "The constraints on the DICOM identifiers that must be supported by the database plugins.",
+            "name": "OrthancPluginIdentifierConstraint",
+            "values": [
+                {
+                    "documentation": "Equal",
+                    "key": "Equal",
+                    "value": 1
+                },
+                {
+                    "documentation": "Less or equal",
+                    "key": "SmallerOrEqual",
+                    "value": 2
+                },
+                {
+                    "documentation": "More or equal",
+                    "key": "GreaterOrEqual",
+                    "value": 3
+                },
+                {
+                    "documentation": "Case-sensitive wildcard matching (with * and ?)",
+                    "key": "Wildcard",
+                    "value": 4
+                }
+            ]
+        },
+        {
+            "documentation": "The image formats that are supported by the Orthanc core.",
+            "name": "OrthancPluginImageFormat",
+            "values": [
+                {
+                    "documentation": "Image compressed using PNG",
+                    "key": "Png",
+                    "value": 0
+                },
+                {
+                    "documentation": "Image compressed using JPEG",
+                    "key": "Jpeg",
+                    "value": 1
+                },
+                {
+                    "documentation": "Image compressed using DICOM",
+                    "key": "Dicom",
+                    "value": 2
+                }
+            ]
+        },
+        {
+            "documentation": "The origin of a DICOM instance that has been received by Orthanc.",
+            "name": "OrthancPluginInstanceOrigin",
+            "values": [
+                {
+                    "documentation": "Unknown origin",
+                    "key": "Unknown",
+                    "value": 1
+                },
+                {
+                    "documentation": "Instance received through DICOM protocol",
+                    "key": "DicomProtocol",
+                    "value": 2
+                },
+                {
+                    "documentation": "Instance received through REST API of Orthanc",
+                    "key": "RestApi",
+                    "value": 3
+                },
+                {
+                    "documentation": "Instance added to Orthanc by a plugin",
+                    "key": "Plugin",
+                    "value": 4
+                },
+                {
+                    "documentation": "Instance added to Orthanc by a Lua script",
+                    "key": "Lua",
+                    "value": 5
+                },
+                {
+                    "documentation": "Instance received through WebDAV (new in 1.8.0)",
+                    "key": "WebDav",
+                    "value": 6
+                }
+            ]
+        },
+        {
+            "documentation": "The possible status for one single step of a job.",
+            "name": "OrthancPluginJobStepStatus",
+            "values": [
+                {
+                    "documentation": "The job has successfully executed all its steps",
+                    "key": "Success",
+                    "value": 1
+                },
+                {
+                    "documentation": "The job has failed while executing this step",
+                    "key": "Failure",
+                    "value": 2
+                },
+                {
+                    "documentation": "The job has still data to process after this step",
+                    "key": "Continue",
+                    "value": 3
+                }
+            ]
+        },
+        {
+            "documentation": "Explains why the job should stop and release the resources it has allocated. This is especially important to disambiguate between the \"paused\" condition and the \"final\" conditions (success, failure, or canceled).",
+            "name": "OrthancPluginJobStopReason",
+            "values": [
+                {
+                    "documentation": "The job has succeeded",
+                    "key": "Success",
+                    "value": 1
+                },
+                {
+                    "documentation": "The job was paused, and will be resumed later",
+                    "key": "Paused",
+                    "value": 2
+                },
+                {
+                    "documentation": "The job has failed, and might be resubmitted later",
+                    "key": "Failure",
+                    "value": 3
+                },
+                {
+                    "documentation": "The job was canceled, and might be resubmitted later",
+                    "key": "Canceled",
+                    "value": 4
+                }
+            ]
+        },
+        {
+            "documentation": "The available types of metrics.",
+            "name": "OrthancPluginMetricsType",
+            "values": [
+                {
+                    "documentation": "Default metrics",
+                    "key": "Default",
+                    "value": 0
+                },
+                {
+                    "documentation": "This metrics represents a time duration. Orthanc will keep the maximum value of the metrics over a sliding window of ten seconds, which is useful if the metrics is sampled frequently.",
+                    "key": "Timer",
+                    "value": 1
+                }
+            ]
+        },
+        {
+            "documentation": "The memory layout of the pixels of an image.",
+            "name": "OrthancPluginPixelFormat",
+            "values": [
+                {
+                    "documentation": "Graylevel 8bpp image. The image is graylevel. Each pixel is unsigned and stored in one byte.",
+                    "key": "Grayscale8",
+                    "value": 1
+                },
+                {
+                    "documentation": "Graylevel, unsigned 16bpp image. The image is graylevel. Each pixel is unsigned and stored in two bytes.",
+                    "key": "Grayscale16",
+                    "value": 2
+                },
+                {
+                    "documentation": "Graylevel, signed 16bpp image. The image is graylevel. Each pixel is signed and stored in two bytes.",
+                    "key": "SignedGrayscale16",
+                    "value": 3
+                },
+                {
+                    "documentation": "Color image in RGB24 format. This format describes a color image. The pixels are stored in 3 consecutive bytes. The memory layout is RGB.",
+                    "key": "RGB24",
+                    "value": 4
+                },
+                {
+                    "documentation": "Color image in RGBA32 format. This format describes a color image. The pixels are stored in 4 consecutive bytes. The memory layout is RGBA.",
+                    "key": "RGBA32",
+                    "value": 5
+                },
+                {
+                    "documentation": "Unknown pixel format",
+                    "key": "Unknown",
+                    "value": 6
+                },
+                {
+                    "documentation": "Color image in RGB48 format. This format describes a color image. The pixels are stored in 6 consecutive bytes. The memory layout is RRGGBB.",
+                    "key": "RGB48",
+                    "value": 7
+                },
+                {
+                    "documentation": "Graylevel, unsigned 32bpp image. The image is graylevel. Each pixel is unsigned and stored in four bytes.",
+                    "key": "Grayscale32",
+                    "value": 8
+                },
+                {
+                    "documentation": "Graylevel, floating-point 32bpp image. The image is graylevel. Each pixel is floating-point and stored in four bytes.",
+                    "key": "Float32",
+                    "value": 9
+                },
+                {
+                    "documentation": "Color image in BGRA32 format. This format describes a color image. The pixels are stored in 4 consecutive bytes. The memory layout is BGRA.",
+                    "key": "BGRA32",
+                    "value": 10
+                },
+                {
+                    "documentation": "Graylevel, unsigned 64bpp image. The image is graylevel. Each pixel is unsigned and stored in eight bytes.",
+                    "key": "Grayscale64",
+                    "value": 11
+                }
+            ]
+        },
+        {
+            "documentation": "The action to be taken after ReceivedInstanceCallback is triggered",
+            "name": "OrthancPluginReceivedInstanceAction",
+            "values": [
+                {
+                    "documentation": "Keep the instance as is",
+                    "key": "KeepAsIs",
+                    "value": 1
+                },
+                {
+                    "documentation": "Modify the instance",
+                    "key": "Modify",
+                    "value": 2
+                },
+                {
+                    "documentation": "Discard the instance",
+                    "key": "Discard",
+                    "value": 3
+                }
+            ]
+        },
+        {
+            "documentation": "The supported types of DICOM resources.",
+            "name": "OrthancPluginResourceType",
+            "values": [
+                {
+                    "documentation": "Patient",
+                    "key": "Patient",
+                    "value": 0
+                },
+                {
+                    "documentation": "Study",
+                    "key": "Study",
+                    "value": 1
+                },
+                {
+                    "documentation": "Series",
+                    "key": "Series",
+                    "value": 2
+                },
+                {
+                    "documentation": "Instance",
+                    "key": "Instance",
+                    "value": 3
+                },
+                {
+                    "documentation": "Unavailable resource type",
+                    "key": "None",
+                    "value": 4
+                }
+            ]
+        },
+        {
+            "documentation": "The available values for the Failure Reason (0008,1197) during storage commitment. http://dicom.nema.org/medical/dicom/2019e/output/chtml/part03/sect_C.14.html#sect_C.14.1.1",
+            "name": "OrthancPluginStorageCommitmentFailureReason",
+            "values": [
+                {
+                    "documentation": "Success: The DICOM instance is properly stored in the SCP",
+                    "key": "Success",
+                    "value": 0
+                },
+                {
+                    "documentation": "0110H: A general failure in processing the operation was encountered",
+                    "key": "ProcessingFailure",
+                    "value": 1
+                },
+                {
+                    "documentation": "0112H: One or more of the elements in the Referenced SOP Instance Sequence was not available",
+                    "key": "NoSuchObjectInstance",
+                    "value": 2
+                },
+                {
+                    "documentation": "0213H: The SCP does not currently have enough resources to store the requested SOP Instance(s)",
+                    "key": "ResourceLimitation",
+                    "value": 3
+                },
+                {
+                    "documentation": "0122H: Storage Commitment has been requested for a SOP Instance with a SOP Class that is not supported by the SCP",
+                    "key": "ReferencedSOPClassNotSupported",
+                    "value": 4
+                },
+                {
+                    "documentation": "0119H: The SOP Class of an element in the Referenced SOP Instance Sequence did not correspond to the SOP class registered for this SOP Instance at the SCP",
+                    "key": "ClassInstanceConflict",
+                    "value": 5
+                },
+                {
+                    "documentation": "0131H: The Transaction UID of the Storage Commitment Request is already in use",
+                    "key": "DuplicateTransactionUID",
+                    "value": 6
+                }
+            ]
+        },
+        {
+            "documentation": "The value representations present in the DICOM standard (version 2013).",
+            "name": "OrthancPluginValueRepresentation",
+            "values": [
+                {
+                    "documentation": "Application Entity",
+                    "key": "AE",
+                    "value": 1
+                },
+                {
+                    "documentation": "Age String",
+                    "key": "AS",
+                    "value": 2
+                },
+                {
+                    "documentation": "Attribute Tag",
+                    "key": "AT",
+                    "value": 3
+                },
+                {
+                    "documentation": "Code String",
+                    "key": "CS",
+                    "value": 4
+                },
+                {
+                    "documentation": "Date",
+                    "key": "DA",
+                    "value": 5
+                },
+                {
+                    "documentation": "Decimal String",
+                    "key": "DS",
+                    "value": 6
+                },
+                {
+                    "documentation": "Date Time",
+                    "key": "DT",
+                    "value": 7
+                },
+                {
+                    "documentation": "Floating Point Double",
+                    "key": "FD",
+                    "value": 8
+                },
+                {
+                    "documentation": "Floating Point Single",
+                    "key": "FL",
+                    "value": 9
+                },
+                {
+                    "documentation": "Integer String",
+                    "key": "IS",
+                    "value": 10
+                },
+                {
+                    "documentation": "Long String",
+                    "key": "LO",
+                    "value": 11
+                },
+                {
+                    "documentation": "Long Text",
+                    "key": "LT",
+                    "value": 12
+                },
+                {
+                    "documentation": "Other Byte String",
+                    "key": "OB",
+                    "value": 13
+                },
+                {
+                    "documentation": "Other Float String",
+                    "key": "OF",
+                    "value": 14
+                },
+                {
+                    "documentation": "Other Word String",
+                    "key": "OW",
+                    "value": 15
+                },
+                {
+                    "documentation": "Person Name",
+                    "key": "PN",
+                    "value": 16
+                },
+                {
+                    "documentation": "Short String",
+                    "key": "SH",
+                    "value": 17
+                },
+                {
+                    "documentation": "Signed Long",
+                    "key": "SL",
+                    "value": 18
+                },
+                {
+                    "documentation": "Sequence of Items",
+                    "key": "SQ",
+                    "value": 19
+                },
+                {
+                    "documentation": "Signed Short",
+                    "key": "SS",
+                    "value": 20
+                },
+                {
+                    "documentation": "Short Text",
+                    "key": "ST",
+                    "value": 21
+                },
+                {
+                    "documentation": "Time",
+                    "key": "TM",
+                    "value": 22
+                },
+                {
+                    "documentation": "Unique Identifier (UID)",
+                    "key": "UI",
+                    "value": 23
+                },
+                {
+                    "documentation": "Unsigned Long",
+                    "key": "UL",
+                    "value": 24
+                },
+                {
+                    "documentation": "Unknown",
+                    "key": "UN",
+                    "value": 25
+                },
+                {
+                    "documentation": "Unsigned Short",
+                    "key": "US",
+                    "value": 26
+                },
+                {
+                    "documentation": "Unlimited Text",
+                    "key": "UT",
+                    "value": 27
+                }
+            ]
+        }
+    ],
+    "global_functions": [
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "expectedMajor",
+                    "sdk_type": "int32_t"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "expectedMinor",
+                    "sdk_type": "int32_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "expectedRevision",
+                    "sdk_type": "int32_t"
+                }
+            ],
+            "c_function": "OrthancPluginCheckVersionAdvanced",
+            "documentation": {
+                "args": {
+                    "expectedMajor": "Expected major version.",
+                    "expectedMinor": "Expected minor version.",
+                    "expectedRevision": "Expected revision."
+                },
+                "description": [
+                    "This function checks whether the version of the Orthanc server running this plugin, is above the given version. Contrarily to OrthancPluginCheckVersion(), it is up to the developer of the plugin to make sure that all the Orthanc SDK services called by the plugin are actually implemented in the given version of Orthanc."
+                ],
+                "return": "1 if and only if the versions are compatible. If the result is 0, the initialization of the plugin should fail.",
+                "summary": "Check that the version of the hosting Orthanc is above a given version."
+            },
+            "return_sdk_type": "int32_t"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginCheckVersion",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function checks whether the version of the Orthanc server running this plugin, is above the version of the current Orthanc SDK header. This guarantees that the plugin is compatible with the hosting Orthanc (i.e. it will not call unavailable services). The result of this function should always be checked in the OrthancPluginInitialize() entry point of the plugin."
+                ],
+                "return": "1 if and only if the versions are compatible. If the result is 0, the initialization of the plugin should fail.",
+                "summary": "Check the compatibility of the plugin wrt. the version of its hosting Orthanc."
+            },
+            "return_sdk_type": "int32_t"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "message",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLogError",
+            "documentation": {
+                "args": {
+                    "message": "The message to be logged."
+                },
+                "description": [
+                    "Log an error message using the Orthanc logging system."
+                ],
+                "summary": "Log an error."
+            },
+            "return_sdk_type": "void"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "message",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLogWarning",
+            "documentation": {
+                "args": {
+                    "message": "The message to be logged."
+                },
+                "description": [
+                    "Log a warning message using the Orthanc logging system."
+                ],
+                "summary": "Log a warning."
+            },
+            "return_sdk_type": "void"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "message",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLogInfo",
+            "documentation": {
+                "args": {
+                    "message": "The message to be logged."
+                },
+                "description": [
+                    "Log an information message using the Orthanc logging system."
+                ],
+                "summary": "Log an information."
+            },
+            "return_sdk_type": "void"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "instanceId",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginGetDicomForInstance",
+            "documentation": {
+                "args": {
+                    "instanceId": "The Orthanc identifier of the DICOM instance of interest.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer()."
+                },
+                "description": [
+                    "Retrieve a DICOM instance using its Orthanc identifier. The DICOM file is stored into a newly allocated memory buffer."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Retrieve a DICOM instance using its Orthanc identifier."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiGet",
+            "documentation": {
+                "args": {
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "uri": "The URI in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a GET call to the built-in Orthanc REST API. The result to the query is stored into a newly allocated memory buffer.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a GET call to the built-in Orthanc REST API."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiGetAfterPlugins",
+            "documentation": {
+                "args": {
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "uri": "The URI in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a GET call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin. The result to the query is stored into a newly allocated memory buffer.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a GET call to the REST API, as tainted by the plugins."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "body",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiPost",
+            "documentation": {
+                "args": {
+                    "body": "The body of the POST request.",
+                    "bodySize": "The size of the body.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "uri": "The URI in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a POST call to the built-in Orthanc REST API. The result to the query is stored into a newly allocated memory buffer.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a POST call to the built-in Orthanc REST API."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "body",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiPostAfterPlugins",
+            "documentation": {
+                "args": {
+                    "body": "The body of the POST request.",
+                    "bodySize": "The size of the body.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "uri": "The URI in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a POST call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin. The result to the query is stored into a newly allocated memory buffer.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a POST call to the REST API, as tainted by the plugins."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiDelete",
+            "documentation": {
+                "args": {
+                    "uri": "The URI to delete in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a DELETE call to the built-in Orthanc REST API.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a DELETE call to the built-in Orthanc REST API."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiDeleteAfterPlugins",
+            "documentation": {
+                "args": {
+                    "uri": "The URI to delete in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a DELETE call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a DELETE call to the REST API, as tainted by the plugins."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "body",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiPut",
+            "documentation": {
+                "args": {
+                    "body": "The body of the PUT request.",
+                    "bodySize": "The size of the body.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "uri": "The URI in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a PUT call to the built-in Orthanc REST API. The result to the query is stored into a newly allocated memory buffer.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a PUT call to the built-in Orthanc REST API."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "body",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginRestApiPutAfterPlugins",
+            "documentation": {
+                "args": {
+                    "body": "The body of the PUT request.",
+                    "bodySize": "The size of the body.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "uri": "The URI in the built-in Orthanc API."
+                },
+                "description": [
+                    "Make a PUT call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin. The result to the query is stored into a newly allocated memory buffer.",
+                    "Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Make a PUT call to the REST API, as tainted by the plugins."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "patientID",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLookupPatient",
+            "documentation": {
+                "args": {
+                    "patientID": "The Patient ID of interest."
+                },
+                "description": [
+                    "Look for a patient stored in Orthanc, using its Patient ID tag (0x0010, 0x0020). This function uses the database index to run as fast as possible (it does not loop over all the stored patients)."
+                ],
+                "return": "The NULL value if the patient is non-existent, or a string containing the Orthanc ID of the patient. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Look for a patient."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "studyUID",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLookupStudy",
+            "documentation": {
+                "args": {
+                    "studyUID": "The Study Instance UID of interest."
+                },
+                "description": [
+                    "Look for a study stored in Orthanc, using its Study Instance UID tag (0x0020, 0x000d). This function uses the database index to run as fast as possible (it does not loop over all the stored studies)."
+                ],
+                "return": "The NULL value if the study is non-existent, or a string containing the Orthanc ID of the study. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Look for a study."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "accessionNumber",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLookupStudyWithAccessionNumber",
+            "documentation": {
+                "args": {
+                    "accessionNumber": "The Accession Number of interest."
+                },
+                "description": [
+                    "Look for a study stored in Orthanc, using its Accession Number tag (0x0008, 0x0050). This function uses the database index to run as fast as possible (it does not loop over all the stored studies)."
+                ],
+                "return": "The NULL value if the study is non-existent, or a string containing the Orthanc ID of the study. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Look for a study, using the accession number."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "seriesUID",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLookupSeries",
+            "documentation": {
+                "args": {
+                    "seriesUID": "The Series Instance UID of interest."
+                },
+                "description": [
+                    "Look for a series stored in Orthanc, using its Series Instance UID tag (0x0020, 0x000e). This function uses the database index to run as fast as possible (it does not loop over all the stored series)."
+                ],
+                "return": "The NULL value if the series is non-existent, or a string containing the Orthanc ID of the series. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Look for a series."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "sopInstanceUID",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginLookupInstance",
+            "documentation": {
+                "args": {
+                    "sopInstanceUID": "The SOP Instance UID of interest."
+                },
+                "description": [
+                    "Look for an instance stored in Orthanc, using its SOP Instance UID tag (0x0008, 0x0018). This function uses the database index to run as fast as possible (it does not loop over all the stored instances)."
+                ],
+                "return": "The NULL value if the instance is non-existent, or a string containing the Orthanc ID of the instance. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Look for an instance."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetOrthancPath",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function returns the path to the Orthanc executable."
+                ],
+                "return": "NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Return the path to the Orthanc executable."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetOrthancDirectory",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function returns the path to the directory containing the Orthanc executable."
+                ],
+                "return": "NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Return the directory containing the Orthanc."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetConfigurationPath",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function returns the path to the configuration file(s) that was specified when starting Orthanc. Since version 0.9.1, this path can refer to a folder that stores a set of configuration files. This function is deprecated in favor of OrthancPluginGetConfiguration()."
+                ],
+                "return": "NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Return the path to the configuration file(s)."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "uri",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginSetRootUri",
+            "documentation": {
+                "args": {
+                    "uri": "The root URI for this plugin."
+                },
+                "description": [
+                    "For plugins that come with a Web interface, this function declares the entry path where to find this interface. This information is notably used in the \"Plugins\" page of Orthanc Explorer."
+                ],
+                "summary": "Set the URI where the plugin provides its Web interface."
+            },
+            "return_sdk_type": "void"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "description",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginSetDescription",
+            "documentation": {
+                "args": {
+                    "description": "The description."
+                },
+                "description": [
+                    "Set a description for this plugin. It is displayed in the \"Plugins\" page of Orthanc Explorer."
+                ],
+                "summary": "Set a description for this plugin."
+            },
+            "return_sdk_type": "void"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "javascript",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginExtendOrthancExplorer",
+            "documentation": {
+                "args": {
+                    "javascript": "The custom JavaScript code."
+                },
+                "description": [
+                    "Add JavaScript code to customize the default behavior of Orthanc Explorer. This can for instance be used to add new buttons."
+                ],
+                "summary": "Extend the JavaScript code of Orthanc Explorer."
+            },
+            "return_sdk_type": "void"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "property",
+                    "sdk_type": "int32_t"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "defaultValue",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginGetGlobalProperty",
+            "documentation": {
+                "args": {
+                    "defaultValue": "The value to return, if the global property is unset.",
+                    "property": "The global property of interest."
+                },
+                "description": [
+                    "Get the value of a global property that is stored in the Orthanc database. Global properties whose index is below 1024 are reserved by Orthanc."
+                ],
+                "return": "The value of the global property, or NULL in the case of an error. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Get the value of a global property."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "property",
+                    "sdk_type": "int32_t"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "value",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginSetGlobalProperty",
+            "documentation": {
+                "args": {
+                    "property": "The global property of interest.",
+                    "value": "The value to be set in the global property."
+                },
+                "description": [
+                    "Set the value of a global property into the Orthanc database. Setting a global property can be used by plugins to save their internal parameters. Plugins are only allowed to set properties whose index are above or equal to 1024 (properties below 1024 are read-only and reserved by Orthanc)."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Set the value of a global property."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetCommandLineArgumentsCount",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "Retrieve the number of command-line arguments that were used to launch Orthanc."
+                ],
+                "return": "The number of arguments.",
+                "summary": "Get the number of command-line arguments."
+            },
+            "return_sdk_type": "uint32_t"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "argument",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginGetCommandLineArgument",
+            "documentation": {
+                "args": {
+                    "argument": "The index of the argument."
+                },
+                "description": [
+                    "Get the value of one of the command-line arguments that were used to launch Orthanc. The number of available arguments can be retrieved by OrthancPluginGetCommandLineArgumentsCount()."
+                ],
+                "return": "The value of the argument, or NULL in the case of an error. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Get the value of a command-line argument."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetExpectedDatabaseVersion",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "Retrieve the expected version of the database schema."
+                ],
+                "return": "The version.",
+                "summary": "Get the expected version of the database schema."
+            },
+            "return_sdk_type": "uint32_t"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetConfiguration",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function returns the content of the configuration that is used by Orthanc, formatted as a JSON string."
+                ],
+                "return": "NULL in the case of an error, or a newly allocated string containing the configuration. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Return the content of the configuration file(s)."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "source",
+                    "sdk_type": "const_void_pointer_with_size"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginCompressionType",
+                    "sdk_name": "compression",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "uncompress",
+                    "sdk_type": "uint8_t"
+                }
+            ],
+            "c_function": "OrthancPluginBufferCompression",
+            "documentation": {
+                "args": {
+                    "compression": "The compression algorithm.",
+                    "size": "The size in bytes of the source buffer.",
+                    "source": "The source buffer.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "uncompress": "If set to \"0\", the buffer must be compressed. If set to \"1\", the buffer must be uncompressed."
+                },
+                "description": [
+                    "This function compresses or decompresses a buffer, using the version of the zlib library that is used by the Orthanc core."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Compress or decompress a buffer."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "path",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginReadFile",
+            "documentation": {
+                "args": {
+                    "path": "The path of the file to be read.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer()."
+                },
+                "description": [
+                    "Read the content of a file on the filesystem, and returns it into a newly allocated memory buffer."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Read a file."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "path",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "data",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginWriteFile",
+            "documentation": {
+                "args": {
+                    "data": "The content of the memory buffer.",
+                    "path": "The path of the file to be written.",
+                    "size": "The size of the memory buffer."
+                },
+                "description": [
+                    "Write the content of a memory buffer to the filesystem."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Write a file."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_enumeration": "OrthancPluginErrorCode",
+                    "sdk_name": "error",
+                    "sdk_type": "enumeration"
+                }
+            ],
+            "c_function": "OrthancPluginGetErrorDescription",
+            "documentation": {
+                "args": {
+                    "error": "The error code of interest."
+                },
+                "description": [
+                    "This function returns the description of a given error code."
+                ],
+                "return": "The error description. This is a statically-allocated string, do not free it.",
+                "summary": "Get the description of a given error code."
+            },
+            "return_sdk_type": "const char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "data",
+                    "sdk_type": "const_void_pointer_with_size"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginImageFormat",
+                    "sdk_name": "format",
+                    "sdk_type": "enumeration"
+                }
+            ],
+            "c_function": "OrthancPluginUncompressImage",
+            "documentation": {
+                "args": {
+                    "data": "Pointer to a memory buffer containing the compressed image.",
+                    "format": "The file format of the compressed image.",
+                    "size": "Size of the memory buffer containing the compressed image."
+                },
+                "description": [
+                    "This function decodes a compressed image from a memory buffer."
+                ],
+                "return": "The uncompressed image. It must be freed with OrthancPluginFreeImage().",
+                "summary": "Decode a compressed image."
+            },
+            "return_sdk_class": "OrthancPluginImage",
+            "return_sdk_type": "object"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_enumeration": "OrthancPluginPixelFormat",
+                    "sdk_name": "format",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "width",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "height",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "pitch",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg4",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const void *"
+                }
+            ],
+            "c_function": "OrthancPluginCompressPngImage",
+            "documentation": {
+                "args": {
+                    "buffer": "The memory buffer containing the uncompressed image.",
+                    "format": "The memory layout of the uncompressed image.",
+                    "height": "The height of the image.",
+                    "pitch": "The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "width": "The width of the image."
+                },
+                "description": [
+                    "This function compresses the given memory buffer containing an image using the PNG specification, and stores the result of the compression into a newly allocated memory buffer."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Encode a PNG image."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_enumeration": "OrthancPluginPixelFormat",
+                    "sdk_name": "format",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "width",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "height",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "pitch",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg4",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const void *"
+                },
+                {
+                    "name": "arg5",
+                    "sdk_name": "quality",
+                    "sdk_type": "uint8_t"
+                }
+            ],
+            "c_function": "OrthancPluginCompressJpegImage",
+            "documentation": {
+                "args": {
+                    "buffer": "The memory buffer containing the uncompressed image.",
+                    "format": "The memory layout of the uncompressed image.",
+                    "height": "The height of the image.",
+                    "pitch": "The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).",
+                    "quality": "The quality of the JPEG encoding, between 1 (worst quality, best compression) and 100 (best quality, worst compression).",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "width": "The width of the image."
+                },
+                "description": [
+                    "This function compresses the given memory buffer containing an image using the JPEG specification, and stores the result of the compression into a newly allocated memory buffer."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Encode a JPEG image."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "url",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "username",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "password",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginHttpGet",
+            "documentation": {
+                "args": {
+                    "password": "The password (can be \"NULL\" if no password protection).",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "url": "The URL of interest.",
+                    "username": "The username (can be \"NULL\" if no password protection)."
+                },
+                "description": [
+                    "Make a HTTP GET call to the given URL. The result to the query is stored into a newly allocated memory buffer. Favor OrthancPluginRestApiGet() if calling the built-in REST API of the Orthanc instance that hosts this plugin."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Issue a HTTP GET call."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "url",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "body",
+                    "sdk_type": "const_void_pointer_with_size"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "username",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg4",
+                    "sdk_name": "password",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginHttpPost",
+            "documentation": {
+                "args": {
+                    "body": "The content of the body of the request.",
+                    "bodySize": "The size of the body of the request.",
+                    "password": "The password (can be \"NULL\" if no password protection).",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "url": "The URL of interest.",
+                    "username": "The username (can be \"NULL\" if no password protection)."
+                },
+                "description": [
+                    "Make a HTTP POST call to the given URL. The result to the query is stored into a newly allocated memory buffer. Favor OrthancPluginRestApiPost() if calling the built-in REST API of the Orthanc instance that hosts this plugin."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Issue a HTTP POST call."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "url",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "body",
+                    "sdk_type": "const_void_pointer_with_size"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "username",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg4",
+                    "sdk_name": "password",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginHttpPut",
+            "documentation": {
+                "args": {
+                    "body": "The content of the body of the request.",
+                    "bodySize": "The size of the body of the request.",
+                    "password": "The password (can be \"NULL\" if no password protection).",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer().",
+                    "url": "The URL of interest.",
+                    "username": "The username (can be \"NULL\" if no password protection)."
+                },
+                "description": [
+                    "Make a HTTP PUT call to the given URL. The result to the query is stored into a newly allocated memory buffer. Favor OrthancPluginRestApiPut() if calling the built-in REST API of the Orthanc instance that hosts this plugin."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Issue a HTTP PUT call."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "url",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "username",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "password",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginHttpDelete",
+            "documentation": {
+                "args": {
+                    "password": "The password (can be \"NULL\" if no password protection).",
+                    "url": "The URL of interest.",
+                    "username": "The username (can be \"NULL\" if no password protection)."
+                },
+                "description": [
+                    "Make a HTTP DELETE call to the given URL. Favor OrthancPluginRestApiDelete() if calling the built-in REST API of the Orthanc instance that hosts this plugin."
+                ],
+                "return": "0 if success, or the error code if failure.",
+                "summary": "Issue a HTTP DELETE call."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetFontsCount",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function returns the number of fonts that are built in the Orthanc core. These fonts can be used to draw texts on images through OrthancPluginDrawText()."
+                ],
+                "return": "The number of fonts.",
+                "summary": "Return the number of available fonts."
+            },
+            "return_sdk_type": "uint32_t"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "fontIndex",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginGetFontName",
+            "documentation": {
+                "args": {
+                    "fontIndex": "The index of the font. This value must be less than OrthancPluginGetFontsCount()."
+                },
+                "description": [
+                    "This function returns the name of a font that is built in the Orthanc core."
+                ],
+                "return": "The font name. This is a statically-allocated string, do not free it.",
+                "summary": "Return the name of a font."
+            },
+            "return_sdk_type": "const char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "fontIndex",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginGetFontSize",
+            "documentation": {
+                "args": {
+                    "fontIndex": "The index of the font. This value must be less than OrthancPluginGetFontsCount()."
+                },
+                "description": [
+                    "This function returns the size of a font that is built in the Orthanc core."
+                ],
+                "return": "The font size.",
+                "summary": "Return the size of a font."
+            },
+            "return_sdk_type": "uint32_t"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "code",
+                    "sdk_type": "int32_t"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "httpStatus",
+                    "sdk_type": "uint16_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "message",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginRegisterErrorCode",
+            "documentation": {
+                "args": {
+                    "code": "The error code that is internal to this plugin.",
+                    "httpStatus": "The HTTP status corresponding to this error.",
+                    "message": "The description of the error."
+                },
+                "description": [
+                    "This function declares a custom error code that can be generated by this plugin. This declaration is used to enrich the body of the HTTP answer in the case of an error, and to set the proper HTTP status code."
+                ],
+                "return": "The error code that has been assigned inside the Orthanc core.",
+                "summary": "Declare a custom error code for this plugin."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "group",
+                    "sdk_type": "uint16_t"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "element",
+                    "sdk_type": "uint16_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginValueRepresentation",
+                    "sdk_name": "vr",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "name",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg4",
+                    "sdk_name": "minMultiplicity",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg5",
+                    "sdk_name": "maxMultiplicity",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginRegisterDictionaryTag",
+            "documentation": {
+                "args": {
+                    "element": "The element of the tag.",
+                    "group": "The group of the tag.",
+                    "maxMultiplicity": "The maximum multiplicity of the tag. A value of 0 means an arbitrary multiplicity (\"\"n\"\").",
+                    "minMultiplicity": "The minimum multiplicity of the tag (must be above 0).",
+                    "name": "The nickname of the tag.",
+                    "vr": "The value representation of the tag."
+                },
+                "description": [
+                    "This function declares a new public tag in the dictionary of DICOM tags that are known to Orthanc. This function should be used in the OrthancPluginInitialize() callback."
+                ],
+                "return": "0 if success, other value if error.",
+                "summary": "Register a new tag into the DICOM dictionary."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "group",
+                    "sdk_type": "uint16_t"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "element",
+                    "sdk_type": "uint16_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginValueRepresentation",
+                    "sdk_name": "vr",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "name",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg4",
+                    "sdk_name": "minMultiplicity",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg5",
+                    "sdk_name": "maxMultiplicity",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg6",
+                    "sdk_name": "privateCreator",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginRegisterPrivateDictionaryTag",
+            "documentation": {
+                "args": {
+                    "element": "The element of the tag.",
+                    "group": "The group of the tag.",
+                    "maxMultiplicity": "The maximum multiplicity of the tag. A value of 0 means an arbitrary multiplicity (\"\"n\"\").",
+                    "minMultiplicity": "The minimum multiplicity of the tag (must be above 0).",
+                    "name": "The nickname of the tag.",
+                    "privateCreator": "The private creator of this private tag.",
+                    "vr": "The value representation of the tag."
+                },
+                "description": [
+                    "This function declares a new private tag in the dictionary of DICOM tags that are known to Orthanc. This function should be used in the OrthancPluginInitialize() callback."
+                ],
+                "return": "0 if success, other value if error.",
+                "summary": "Register a new private tag into the DICOM dictionary."
+            },
+            "return_sdk_enumeration": "OrthancPluginErrorCode",
+            "return_sdk_type": "enumeration"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const_void_pointer_with_size"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginDicomToJsonFormat",
+                    "sdk_name": "format",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_enumeration": "OrthancPluginDicomToJsonFlags",
+                    "sdk_name": "flags",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg4",
+                    "sdk_name": "maxStringLength",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginDicomBufferToJson",
+            "documentation": {
+                "args": {
+                    "buffer": "The memory buffer containing the DICOM file.",
+                    "flags": "Flags governing the output.",
+                    "format": "The output format.",
+                    "maxStringLength": "The maximum length of a field. Too long fields will be output as \"null\". The 0 value means no maximum length.",
+                    "size": "The size of the memory buffer."
+                },
+                "description": [
+                    "This function takes as input a memory buffer containing a DICOM file, and outputs a JSON string representing the tags of this DICOM file."
+                ],
+                "return": "The NULL value if the case of an error, or the JSON string. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Format a DICOM memory buffer as a JSON string."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "instanceId",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_enumeration": "OrthancPluginDicomToJsonFormat",
+                    "sdk_name": "format",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginDicomToJsonFlags",
+                    "sdk_name": "flags",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "maxStringLength",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginDicomInstanceToJson",
+            "documentation": {
+                "args": {
+                    "flags": "Flags governing the output.",
+                    "format": "The output format.",
+                    "instanceId": "The Orthanc identifier of the instance.",
+                    "maxStringLength": "The maximum length of a field. Too long fields will be output as \"null\". The 0 value means no maximum length."
+                },
+                "description": [
+                    "This function formats a DICOM instance that is stored in Orthanc, and outputs a JSON string representing the tags of this DICOM instance."
+                ],
+                "return": "The NULL value if the case of an error, or the JSON string. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Format a DICOM instance as a JSON string."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "json",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_class": "OrthancPluginImage",
+                    "sdk_name": "pixelData",
+                    "sdk_type": "const_object"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginCreateDicomFlags",
+                    "sdk_name": "flags",
+                    "sdk_type": "enumeration"
+                }
+            ],
+            "c_function": "OrthancPluginCreateDicom",
+            "documentation": {
+                "args": {
+                    "flags": "Flags governing the output.",
+                    "json": "The input JSON file.",
+                    "pixelData": "The image. Can be NULL, if the pixel data is encoded inside the JSON with the data URI scheme.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer()."
+                },
+                "description": [
+                    "This function takes as input a string containing a JSON file describing the content of a DICOM instance. As an output, it writes the corresponding DICOM instance to a newly allocated memory buffer. Additionally, an image to be encoded within the DICOM instance can also be provided.",
+                    "Private tags will be associated with the private creator whose value is specified in the \"DefaultPrivateCreator\" configuration option of Orthanc. The function OrthancPluginCreateDicom2() can be used if another private creator must be used to create this instance."
+                ],
+                "return": "0 if success, other value if error.",
+                "summary": "Create a DICOM instance from a JSON string and an image."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_enumeration": "OrthancPluginPixelFormat",
+                    "sdk_name": "format",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "width",
+                    "sdk_type": "uint32_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "height",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginCreateImage",
+            "documentation": {
+                "args": {
+                    "format": "The format of the pixels.",
+                    "height": "The height of the image.",
+                    "width": "The width of the image."
+                },
+                "description": [
+                    "This function creates an image of given size and format."
+                ],
+                "return": "The newly allocated image. It must be freed with OrthancPluginFreeImage().",
+                "summary": "Create an image."
+            },
+            "return_sdk_class": "OrthancPluginImage",
+            "return_sdk_type": "object"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const_void_pointer_with_size"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "frameIndex",
+                    "sdk_type": "uint32_t"
+                }
+            ],
+            "c_function": "OrthancPluginDecodeDicomImage",
+            "documentation": {
+                "args": {
+                    "buffer": "Pointer to a memory buffer containing the DICOM image.",
+                    "bufferSize": "Size of the memory buffer containing the DICOM image.",
+                    "frameIndex": "The index of the frame of interest in a multi-frame image."
+                },
+                "description": [
+                    "This function decodes one frame of a DICOM image that is stored in a memory buffer. This function will give the same result as OrthancPluginUncompressImage() for single-frame DICOM images."
+                ],
+                "return": "The uncompressed image. It must be freed with OrthancPluginFreeImage().",
+                "summary": "Decode one frame from a DICOM instance."
+            },
+            "return_sdk_class": "OrthancPluginImage",
+            "return_sdk_type": "object"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginComputeMd5",
+            "documentation": {
+                "args": {
+                    "buffer": "The source memory buffer.",
+                    "size": "The size in bytes of the source buffer."
+                },
+                "description": [
+                    "This functions computes the MD5 cryptographic hash of the given memory buffer."
+                ],
+                "return": "The NULL value in case of error, or a string containing the cryptographic hash. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Compute an MD5 hash."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginComputeSha1",
+            "documentation": {
+                "args": {
+                    "buffer": "The source memory buffer.",
+                    "size": "The size in bytes of the source buffer."
+                },
+                "description": [
+                    "This functions computes the SHA-1 cryptographic hash of the given memory buffer."
+                ],
+                "return": "The NULL value in case of error, or a string containing the cryptographic hash. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Compute a SHA-1 hash."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGenerateUuid",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "Generate a random GUID/UUID (globally unique identifier)."
+                ],
+                "return": "NULL in the case of an error, or a newly allocated string containing the UUID. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Generate an UUID."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "query",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginCreateFindMatcher",
+            "documentation": {
+                "args": {
+                    "query": "The C-Find DICOM query.",
+                    "size": "The size of the DICOM query."
+                },
+                "description": [
+                    "This function creates a \"matcher\" object that can be used to check whether a DICOM instance matches a C-Find query. The C-Find query must be expressed as a DICOM buffer."
+                ],
+                "return": "The newly allocated matcher. It must be freed with OrthancPluginFreeFindMatcher().",
+                "summary": "Create a C-Find matcher."
+            },
+            "return_sdk_class": "OrthancPluginFindMatcher",
+            "return_sdk_type": "object"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGetPeers",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function returns the parameters of the Orthanc peers that are known to the Orthanc server hosting the plugin."
+                ],
+                "return": "NULL if error, or a newly allocated opaque data structure containing the peers. This structure must be freed with OrthancPluginFreePeers().",
+                "summary": "Return the list of available Orthanc peers."
+            },
+            "return_sdk_class": "OrthancPluginPeers",
+            "return_sdk_type": "object"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "path",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginAutodetectMimeType",
+            "documentation": {
+                "args": {
+                    "path": "Path to the file."
+                },
+                "description": [
+                    "This function returns the MIME type of a file by inspecting its extension."
+                ],
+                "return": "The MIME type. This is a statically-allocated string, do not free it.",
+                "summary": "Detect the MIME type of a file."
+            },
+            "return_sdk_type": "const char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "name",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "value",
+                    "sdk_type": "float"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginMetricsType",
+                    "sdk_name": "type",
+                    "sdk_type": "enumeration"
+                }
+            ],
+            "c_function": "OrthancPluginSetMetricsValue",
+            "documentation": {
+                "args": {
+                    "name": "The name of the metrics to be set.",
+                    "type": "The type of the metrics. This parameter is only taken into consideration the first time this metrics is set.",
+                    "value": "The value of the metrics."
+                },
+                "description": [
+                    "This function sets the value of a metrics to monitor the behavior of the plugin through tools such as Prometheus. The values of all the metrics are stored within the Orthanc context."
+                ],
+                "summary": "Set the value of a metrics."
+            },
+            "return_sdk_type": "void"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "group",
+                    "sdk_type": "uint16_t"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_name": "element",
+                    "sdk_type": "uint16_t"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "privateCreator",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginGetTagName",
+            "documentation": {
+                "args": {
+                    "element": "The element of the tag.",
+                    "group": "The group of the tag.",
+                    "privateCreator": "For private tags, the name of the private creator (can be NULL)."
+                },
+                "description": [
+                    "This function makes a lookup to the dictionary of DICOM tags that are known to Orthanc, and returns the symbolic name of a DICOM tag."
+                ],
+                "return": "NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Returns the symbolic name of a DICOM tag."
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const_void_pointer_with_size"
+                }
+            ],
+            "c_function": "OrthancPluginCreateDicomInstance",
+            "documentation": {
+                "args": {
+                    "buffer": "The memory buffer containing the DICOM instance.",
+                    "size": "The size of the memory buffer."
+                },
+                "description": [
+                    "This function parses a memory buffer that contains a DICOM file. The function returns a new pointer to a data structure that is managed by the Orthanc core."
+                ],
+                "return": "The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().",
+                "summary": "Parse a DICOM instance."
+            },
+            "return_sdk_class": "OrthancPluginDicomInstance",
+            "return_sdk_type": "object"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "buffer",
+                    "sdk_type": "const_void_pointer_with_size"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_name": "transferSyntax",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginTranscodeDicomInstance",
+            "documentation": {
+                "args": {
+                    "buffer": "The memory buffer containing the DICOM instance.",
+                    "size": "The size of the memory buffer.",
+                    "transferSyntax": "The transfer syntax UID for the transcoding."
+                },
+                "description": [
+                    "This function parses a memory buffer that contains a DICOM file, then transcodes it to the given transfer syntax. The function returns a new pointer to a data structure that is managed by the Orthanc core."
+                ],
+                "return": "The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().",
+                "summary": "Parse and transcode a DICOM instance."
+            },
+            "return_sdk_class": "OrthancPluginDicomInstance",
+            "return_sdk_type": "object"
+        },
+        {
+            "args": [],
+            "c_function": "OrthancPluginGenerateRestApiAuthorizationToken",
+            "documentation": {
+                "args": {},
+                "description": [
+                    "This function generates a token that can be set in the HTTP header \"Authorization\" so as to grant full access to the REST API of Orthanc using an external HTTP client. Using this function avoids the need of adding a separate user in the \"RegisteredUsers\" configuration of Orthanc, which eases deployments.",
+                    "This feature is notably useful in multiprocess scenarios, where a subprocess created by a plugin has no access to the \"OrthancPluginContext\", and thus cannot call \"OrthancPluginRestApi[Get|Post|Put|Delete]()\".",
+                    "This situation is frequently encountered in Python plugins, where the \"multiprocessing\" package can be used to bypass the Global Interpreter Lock (GIL) and thus to improve performance and concurrency."
+                ],
+                "return": "The authorization token, or NULL value in the case of an error. This string must be freed by OrthancPluginFreeString().",
+                "summary": "Generate a token to grant full access to the REST API of Orthanc"
+            },
+            "return_sdk_type": "char *"
+        },
+        {
+            "args": [
+                {
+                    "name": "arg0",
+                    "sdk_name": "json",
+                    "sdk_type": "const char *"
+                },
+                {
+                    "name": "arg1",
+                    "sdk_class": "OrthancPluginImage",
+                    "sdk_name": "pixelData",
+                    "sdk_type": "const_object"
+                },
+                {
+                    "name": "arg2",
+                    "sdk_enumeration": "OrthancPluginCreateDicomFlags",
+                    "sdk_name": "flags",
+                    "sdk_type": "enumeration"
+                },
+                {
+                    "name": "arg3",
+                    "sdk_name": "privateCreator",
+                    "sdk_type": "const char *"
+                }
+            ],
+            "c_function": "OrthancPluginCreateDicom2",
+            "documentation": {
+                "args": {
+                    "flags": "Flags governing the output.",
+                    "json": "The input JSON file.",
+                    "pixelData": "The image. Can be NULL, if the pixel data is encoded inside the JSON with the data URI scheme.",
+                    "privateCreator": "The private creator to be used for the private DICOM tags. Check out the global configuration option \"Dictionary\" of Orthanc.",
+                    "target": "The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer()."
+                },
+                "description": [
+                    "This function takes as input a string containing a JSON file describing the content of a DICOM instance. As an output, it writes the corresponding DICOM instance to a newly allocated memory buffer. Additionally, an image to be encoded within the DICOM instance can also be provided.",
+                    "Contrarily to the function OrthancPluginCreateDicom(), this function can be explicitly provided with a private creator."
+                ],
+                "return": "0 if success, other value if error.",
+                "summary": "Create a DICOM instance from a JSON string and an image, with a private creator."
+            },
+            "return_sdk_type": "OrthancPluginMemoryBuffer *"
+        }
+    ]
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Sdk-1.10.0/CodeModel.json.license	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,2 @@
+# SPDX-FileCopyrightText: 2023-2024 Sebastien Jodogne, UCLouvain, Belgium
+# SPDX-License-Identifier: GPL-3.0-or-later
--- a/Resources/OrthancCPlugin-1.10.0.patch	Tue Jul 02 17:17:24 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
---- OrthancCPlugin.h.orig	2023-10-14 17:06:44.406226125 +0200
-+++ OrthancCPlugin.h	2023-10-14 17:09:26.978745058 +0200
-@@ -837,7 +837,7 @@
-    **/
-   typedef enum
-   {
--    OrthancPluginDicomToJsonFlags_None                  = 0,
-+    OrthancPluginDicomToJsonFlags_None                  = 0,         /*!< Default formatting */
-     OrthancPluginDicomToJsonFlags_IncludeBinary         = (1 << 0),  /*!< Include the binary tags */
-     OrthancPluginDicomToJsonFlags_IncludePrivateTags    = (1 << 1),  /*!< Include the private tags */
-     OrthancPluginDicomToJsonFlags_IncludeUnknownTags    = (1 << 2),  /*!< Include the tags unknown by the dictionary */
-@@ -858,7 +858,7 @@
-    **/
-   typedef enum
-   {
--    OrthancPluginCreateDicomFlags_None                  = 0,
-+    OrthancPluginCreateDicomFlags_None                  = 0,         /*!< Default mode */
-     OrthancPluginCreateDicomFlags_DecodeDataUriScheme   = (1 << 0),  /*!< Decode fields encoded using data URI scheme */
-     OrthancPluginCreateDicomFlags_GenerateIdentifiers   = (1 << 1),  /*!< Automatically generate DICOM identifiers */
- 
-@@ -975,32 +975,46 @@
-    **/
-   typedef enum
-   {
-+    /**
-+     * Success: The DICOM instance is properly stored in the SCP
-+     **/
-     OrthancPluginStorageCommitmentFailureReason_Success = 0,
--    /*!< Success: The DICOM instance is properly stored in the SCP */
- 
-+    /**
-+     * 0110H: A general failure in processing the operation was encountered
-+     **/
-     OrthancPluginStorageCommitmentFailureReason_ProcessingFailure = 1,
--    /*!< 0110H: A general failure in processing the operation was encountered */
- 
-+    /**
-+     * 0112H: One or more of the elements in the Referenced SOP
-+     * Instance Sequence was not available
-+     **/
-     OrthancPluginStorageCommitmentFailureReason_NoSuchObjectInstance = 2,
--    /*!< 0112H: One or more of the elements in the Referenced SOP
--      Instance Sequence was not available */
- 
-+    /**
-+     * 0213H: The SCP does not currently have enough resources to
-+     * store the requested SOP Instance(s)
-+     **/
-     OrthancPluginStorageCommitmentFailureReason_ResourceLimitation = 3,
--    /*!< 0213H: The SCP does not currently have enough resources to
--      store the requested SOP Instance(s) */
- 
-+    /**
-+     * 0122H: Storage Commitment has been requested for a SOP Instance
-+     * with a SOP Class that is not supported by the SCP
-+     **/
-     OrthancPluginStorageCommitmentFailureReason_ReferencedSOPClassNotSupported = 4,
--    /*!< 0122H: Storage Commitment has been requested for a SOP
--      Instance with a SOP Class that is not supported by the SCP */
- 
-+    /**
-+     * 0119H: The SOP Class of an element in the Referenced SOP
-+     * Instance Sequence did not correspond to the SOP class
-+     * registered for this SOP Instance at the SCP
-+     **/
-     OrthancPluginStorageCommitmentFailureReason_ClassInstanceConflict = 5,
--    /*!< 0119H: The SOP Class of an element in the Referenced SOP
--      Instance Sequence did not correspond to the SOP class registered
--      for this SOP Instance at the SCP */
- 
-+    /**
-+     * 0131H: The Transaction UID of the Storage Commitment Request is
-+     * already in use
-+     **/
-     OrthancPluginStorageCommitmentFailureReason_DuplicateTransactionUID = 6
--    /*!< 0131H: The Transaction UID of the Storage Commitment Request
--      is already in use */
-   } OrthancPluginStorageCommitmentFailureReason;
- 
- 
-@@ -1829,15 +1843,16 @@
-    * @see OrthancPluginCheckVersion
-    * @ingroup Callbacks
-    **/
--  ORTHANC_PLUGIN_INLINE int  OrthancPluginCheckVersionAdvanced(
-+  ORTHANC_PLUGIN_INLINE int32_t  OrthancPluginCheckVersionAdvanced(
-     OrthancPluginContext* context,
--    int expectedMajor,
--    int expectedMinor,
--    int expectedRevision)
-+    int32_t expectedMajor,
-+    int32_t expectedMinor,
-+    int32_t expectedRevision)
-   {
--    int major, minor, revision;
-+    int32_t major, minor, revision;
- 
--    if (sizeof(int32_t) != sizeof(OrthancPluginErrorCode) ||
-+    if (sizeof(int) != sizeof(int32_t) || /* Ensure binary compatibility with Orthanc SDK <= 1.12.1 */
-+        sizeof(int32_t) != sizeof(OrthancPluginErrorCode) ||
-         sizeof(int32_t) != sizeof(OrthancPluginHttpMethod) ||
-         sizeof(int32_t) != sizeof(_OrthancPluginService) ||
-         sizeof(int32_t) != sizeof(_OrthancPluginProperty) ||
-@@ -1935,7 +1950,7 @@
-    * @see OrthancPluginCheckVersionAdvanced
-    * @ingroup Callbacks
-    **/
--  ORTHANC_PLUGIN_INLINE int  OrthancPluginCheckVersion(
-+  ORTHANC_PLUGIN_INLINE int32_t  OrthancPluginCheckVersion(
-     OrthancPluginContext* context)
-   {
-     return OrthancPluginCheckVersionAdvanced(
-@@ -3077,7 +3092,7 @@
-    * @return 1 if the metadata is present, 0 if it is absent, -1 in case of error.
-    * @ingroup DicomInstance
-    **/
--  ORTHANC_PLUGIN_INLINE int  OrthancPluginHasInstanceMetadata(
-+  ORTHANC_PLUGIN_INLINE int32_t  OrthancPluginHasInstanceMetadata(
-     OrthancPluginContext*              context,
-     const OrthancPluginDicomInstance*  instance,
-     const char*                        metadata)
-@@ -3856,13 +3871,13 @@
-     OrthancPluginContext*    context,
-     OrthancPluginRestOutput* output,
-     uint16_t                 status,
--    const char*              body,
-+    const void*              body,
-     uint32_t                 bodySize)
-   {
-     _OrthancPluginSendHttpStatus params;
-     params.output = output;
-     params.status = status;
--    params.body = body;
-+    params.body = reinterpret_cast<const char*>(body);
-     params.bodySize = bodySize;
-     context->InvokeService(context, _OrthancPluginService_SendHttpStatus, &params);
-   }
-@@ -6760,7 +6775,7 @@
-   {
-     char**             resultId;
-     OrthancPluginJob  *job;
--    int                priority;
-+    int32_t            priority;
-   } _OrthancPluginSubmitJob;
- 
-   /**
-@@ -6779,7 +6794,7 @@
-   ORTHANC_PLUGIN_INLINE char *OrthancPluginSubmitJob(
-     OrthancPluginContext   *context,
-     OrthancPluginJob       *job,
--    int                     priority)
-+    int32_t                 priority)
-   {
-     char* resultId = NULL;
- 
--- a/Resources/OrthancCPlugin-1.5.7.patch	Tue Jul 02 17:17:24 2024 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
---- OrthancCPlugin.h.orig	2020-03-26 16:23:11.963320239 +0100
-+++ OrthancCPlugin.h	2020-03-26 16:24:45.403002064 +0100
-@@ -909,14 +909,14 @@
-    **/
-   typedef enum
-   {
--    OrthancPluginMetricsType_Default,   /*!< Default metrics */
-+    OrthancPluginMetricsType_Default = 0,   /*!< Default metrics */
- 
-     /**
-      * This metrics represents a time duration. Orthanc will keep the
-      * maximum value of the metrics over a sliding window of ten
-      * seconds, which is useful if the metrics is sampled frequently.
-      **/
--    OrthancPluginMetricsType_Timer
-+    OrthancPluginMetricsType_Timer = 1
-   } OrthancPluginMetricsType;
-   
- 
-@@ -926,9 +926,9 @@
-    **/
-   typedef enum
-   {
--    OrthancPluginDicomWebBinaryMode_Ignore,        /*!< Don't include binary tags */
--    OrthancPluginDicomWebBinaryMode_InlineBinary,  /*!< Inline encoding using Base64 */
--    OrthancPluginDicomWebBinaryMode_BulkDataUri    /*!< Use a bulk data URI field */
-+    OrthancPluginDicomWebBinaryMode_Ignore = 0,        /*!< Don't include binary tags */
-+    OrthancPluginDicomWebBinaryMode_InlineBinary = 1,  /*!< Inline encoding using Base64 */
-+    OrthancPluginDicomWebBinaryMode_BulkDataUri = 2    /*!< Use a bulk data URI field */
-   } OrthancPluginDicomWebBinaryMode;
- 
-   
-@@ -1915,7 +1915,7 @@
-   typedef struct
-   {
-     OrthancPluginRestOutput* output;
--    const char*              answer;
-+    const void*              answer;
-     uint32_t                 answerSize;
-     const char*              mimeType;
-   } _OrthancPluginAnswerBuffer;
-@@ -1935,7 +1935,7 @@
-   ORTHANC_PLUGIN_INLINE void OrthancPluginAnswerBuffer(
-     OrthancPluginContext*    context,
-     OrthancPluginRestOutput* output,
--    const char*              answer,
-+    const void*              answer,
-     uint32_t                 answerSize,
-     const char*              mimeType)
-   {
-@@ -2732,7 +2732,7 @@
-    * @return The pointer to the DICOM data, NULL in case of error.
-    * @ingroup Callbacks
-    **/
--  ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetInstanceData(
-+  ORTHANC_PLUGIN_INLINE const void* OrthancPluginGetInstanceData(
-     OrthancPluginContext*        context,
-     OrthancPluginDicomInstance*  instance)
-   {
--- a/Resources/SyncOrthancFolder.py	Tue Jul 02 17:17:24 2024 +0200
+++ b/Resources/SyncOrthancFolder.py	Tue Jul 02 19:06:54 2024 +0200
@@ -12,8 +12,10 @@
 import urllib.request
 
 TARGET = os.path.join(os.path.dirname(__file__), 'Orthanc')
+ORTHANC_JAVA_VERSION = '1.0'
 PLUGIN_SDK_VERSION = '1.10.0'
-REPOSITORY = 'https://orthanc.uclouvain.be/hg/orthanc/raw-file'
+ORTHANC_CORE_REPOSITORY = 'https://orthanc.uclouvain.be/hg/orthanc/raw-file'
+ORTHANC_JAVA_REPOSITORY = 'https://orthanc.uclouvain.be/hg/orthanc-java/raw-file'
 
 FILES = [
     ('OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake', 'CMake'),
@@ -34,15 +36,12 @@
     ('OrthancServer/Plugins/Samples/Common/VersionScriptPlugins.map', 'Plugins'),
 ]
 
-SDK = [
-    'orthanc/OrthancCPlugin.h',
-]
-
 
 def Download(x):
-    branch = x[0]
-    source = x[1]
-    target = os.path.join(TARGET, x[2])
+    repository = x[0]
+    branch = x[1]
+    source = x[2]
+    target = os.path.join(TARGET, x[3])
     print(target)
 
     try:
@@ -50,7 +49,7 @@
     except:
         pass
 
-    url = '%s/%s/%s' % (REPOSITORY, branch, source)
+    url = '%s/%s/%s' % (repository, branch, source)
 
     with open(target, 'wb') as f:
         try:
@@ -63,26 +62,35 @@
 commands = []
 
 for f in FILES:
-    commands.append([ 'default',
-                      f[0],
-                      os.path.join(f[1], os.path.basename(f[0])) ])
+    commands.append([
+        ORTHANC_CORE_REPOSITORY,
+        'default',
+        f[0],
+        os.path.join(f[1], os.path.basename(f[0]))
+    ])
+
 
-for f in SDK:
+commands.append([
+    ORTHANC_JAVA_REPOSITORY,
+    'OrthancJava-%s' % ORTHANC_JAVA_VERSION,
+    'Resources/Orthanc/Sdk-%s/orthanc/OrthancCPlugin.h' % PLUGIN_SDK_VERSION,
+    'Sdk-%s/orthanc/OrthancCPlugin.h' % PLUGIN_SDK_VERSION,
+])
+
+
+for f in [
+        'CodeModel.json',
+        'CodeModel.json.license',
+        'ClassDocumentation.json',
+        'ClassDocumentation.json.license',
+        ]:
     commands.append([
-        'Orthanc-%s' % PLUGIN_SDK_VERSION, 
-        'OrthancServer/Plugins/Include/%s' % f,
-        'Sdk-%s/%s' % (PLUGIN_SDK_VERSION, f) 
+        ORTHANC_JAVA_REPOSITORY,
+        'OrthancJava-%s' % ORTHANC_JAVA_VERSION,
+        'CodeGeneration/%s' % f,
+        'Sdk-%s/%s' % (PLUGIN_SDK_VERSION, f),
     ])
 
 
 pool = multiprocessing.Pool(10)  # simultaneous downloads
 pool.map(Download, commands)
-
-# Patch the SDK, if need be
-patch = os.path.join(os.path.abspath(os.path.dirname(__file__)),
-                     'OrthancCPlugin-%s.patch' % PLUGIN_SDK_VERSION)
-if os.path.exists(patch):
-    subprocess.check_call([ 'patch', '-p0', '-i', patch ],
-                          cwd = os.path.join(os.path.dirname(__file__),
-                                             'Orthanc',
-                                             'Sdk-%s' % PLUGIN_SDK_VERSION, 'orthanc'))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sources/Autogenerated/orthanc.pyi	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,2788 @@
+##
+## Python plugin for Orthanc
+## Copyright (C) 2020-2023 Osimis S.A., Belgium
+## Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+## Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+##
+## This program is free software: you can redistribute it and/or
+## modify it under the terms of the GNU Affero 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
+## Affero General Public License for more details.
+##
+## You should have received a copy of the GNU Affero General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+
+# WARNING: Auto-generated file. Do not modify it by hand.
+
+
+import enum
+import typing
+
+
+
+class ChangeType(enum.Enum):
+    """
+    The supported types of changes that can be signaled to the change callback.
+    """
+
+    """
+    Series is now complete
+    """
+    COMPLETED_SERIES: int = 0,
+
+    """
+    Deleted resource
+    """
+    DELETED: int = 1,
+
+    """
+    A new instance was added to this resource
+    """
+    NEW_CHILD_INSTANCE: int = 2,
+
+    """
+    New instance received
+    """
+    NEW_INSTANCE: int = 3,
+
+    """
+    New patient created
+    """
+    NEW_PATIENT: int = 4,
+
+    """
+    New series created
+    """
+    NEW_SERIES: int = 5,
+
+    """
+    New study created
+    """
+    NEW_STUDY: int = 6,
+
+    """
+    Timeout: No new instance in this patient
+    """
+    STABLE_PATIENT: int = 7,
+
+    """
+    Timeout: No new instance in this series
+    """
+    STABLE_SERIES: int = 8,
+
+    """
+    Timeout: No new instance in this study
+    """
+    STABLE_STUDY: int = 9,
+
+    """
+    Orthanc has started
+    """
+    ORTHANC_STARTED: int = 10,
+
+    """
+    Orthanc is stopping
+    """
+    ORTHANC_STOPPED: int = 11,
+
+    """
+    Some user-defined attachment has changed for this resource
+    """
+    UPDATED_ATTACHMENT: int = 12,
+
+    """
+    Some user-defined metadata has changed for this resource
+    """
+    UPDATED_METADATA: int = 13,
+
+    """
+    The list of Orthanc peers has changed
+    """
+    UPDATED_PEERS: int = 14,
+
+    """
+    The list of DICOM modalities has changed
+    """
+    UPDATED_MODALITIES: int = 15,
+
+    """
+    New Job submitted
+    """
+    JOB_SUBMITTED: int = 16,
+
+    """
+    A Job has completed successfully
+    """
+    JOB_SUCCESS: int = 17,
+
+    """
+    A Job has failed
+    """
+    JOB_FAILURE: int = 18,
+
+class CompressionType(enum.Enum):
+    """
+    The compression algorithms that are supported by the Orthanc core.
+    """
+
+    """
+    Standard zlib compression
+    """
+    ZLIB: int = 0,
+
+    """
+    zlib, prefixed with uncompressed size (uint64_t)
+    """
+    ZLIB_WITH_SIZE: int = 1,
+
+    """
+    Standard gzip compression
+    """
+    GZIP: int = 2,
+
+    """
+    gzip, prefixed with uncompressed size (uint64_t)
+    """
+    GZIP_WITH_SIZE: int = 3,
+
+class ConstraintType(enum.Enum):
+    """
+    The constraints on the tags (main DICOM tags and identifier tags) that must be supported by the database plugins.
+    """
+
+    """
+    Equal
+    """
+    EQUAL: int = 1,
+
+    """
+    Less or equal
+    """
+    SMALLER_OR_EQUAL: int = 2,
+
+    """
+    More or equal
+    """
+    GREATER_OR_EQUAL: int = 3,
+
+    """
+    Wildcard matching
+    """
+    WILDCARD: int = 4,
+
+    """
+    List of values
+    """
+    LIST: int = 5,
+
+class ContentType(enum.Enum):
+    """
+    The content types that are supported by Orthanc plugins.
+    """
+
+    """
+    Unknown content type
+    """
+    UNKNOWN: int = 0,
+
+    """
+    DICOM
+    """
+    DICOM: int = 1,
+
+    """
+    JSON summary of a DICOM file
+    """
+    DICOM_AS_JSON: int = 2,
+
+    """
+    DICOM Header till pixel data
+    """
+    DICOM_UNTIL_PIXEL_DATA: int = 3,
+
+class CreateDicomFlags(enum.Enum):
+    """
+    Flags to the creation of a DICOM file.
+    """
+
+    """
+    Default mode
+    """
+    NONE: int = 0,
+
+    """
+    Decode fields encoded using data URI scheme
+    """
+    DECODE_DATA_URI_SCHEME: int = 1,
+
+    """
+    Automatically generate DICOM identifiers
+    """
+    GENERATE_IDENTIFIERS: int = 2,
+
+class DicomToJsonFlags(enum.Enum):
+    """
+    Flags to customize a DICOM-to-JSON conversion. By default, binary tags are formatted using Data URI scheme.
+    """
+
+    """
+    Default formatting
+    """
+    NONE: int = 0,
+
+    """
+    Include the binary tags
+    """
+    INCLUDE_BINARY: int = 1,
+
+    """
+    Include the private tags
+    """
+    INCLUDE_PRIVATE_TAGS: int = 2,
+
+    """
+    Include the tags unknown by the dictionary
+    """
+    INCLUDE_UNKNOWN_TAGS: int = 4,
+
+    """
+    Include the pixel data
+    """
+    INCLUDE_PIXEL_DATA: int = 8,
+
+    """
+    Output binary tags as-is, dropping non-ASCII
+    """
+    CONVERT_BINARY_TO_ASCII: int = 16,
+
+    """
+    Signal binary tags as null values
+    """
+    CONVERT_BINARY_TO_NULL: int = 32,
+
+    """
+    Stop processing after pixel data (new in 1.9.1)
+    """
+    STOP_AFTER_PIXEL_DATA: int = 64,
+
+    """
+    Skip tags whose element is zero (new in 1.9.1)
+    """
+    SKIP_GROUP_LENGTHS: int = 128,
+
+class DicomToJsonFormat(enum.Enum):
+    """
+    The possible output formats for a DICOM-to-JSON conversion.
+    """
+
+    """
+    Full output, with most details
+    """
+    FULL: int = 1,
+
+    """
+    Tags output as hexadecimal numbers
+    """
+    SHORT: int = 2,
+
+    """
+    Human-readable JSON
+    """
+    HUMAN: int = 3,
+
+class DicomWebBinaryMode(enum.Enum):
+    """
+    The available modes to export a binary DICOM tag into a DICOMweb JSON or XML document.
+    """
+
+    """
+    Don't include binary tags
+    """
+    IGNORE: int = 0,
+
+    """
+    Inline encoding using Base64
+    """
+    INLINE_BINARY: int = 1,
+
+    """
+    Use a bulk data URI field
+    """
+    BULK_DATA_URI: int = 2,
+
+class ErrorCode(enum.Enum):
+    """
+    The various error codes that can be returned by the Orthanc core.
+    """
+
+    """
+    Internal error
+    """
+    INTERNAL_ERROR: int = -1,
+
+    """
+    Success
+    """
+    SUCCESS: int = 0,
+
+    """
+    Error encountered within the plugin engine
+    """
+    PLUGIN: int = 1,
+
+    """
+    Not implemented yet
+    """
+    NOT_IMPLEMENTED: int = 2,
+
+    """
+    Parameter out of range
+    """
+    PARAMETER_OUT_OF_RANGE: int = 3,
+
+    """
+    The server hosting Orthanc is running out of memory
+    """
+    NOT_ENOUGH_MEMORY: int = 4,
+
+    """
+    Bad type for a parameter
+    """
+    BAD_PARAMETER_TYPE: int = 5,
+
+    """
+    Bad sequence of calls
+    """
+    BAD_SEQUENCE_OF_CALLS: int = 6,
+
+    """
+    Accessing an inexistent item
+    """
+    INEXISTENT_ITEM: int = 7,
+
+    """
+    Bad request
+    """
+    BAD_REQUEST: int = 8,
+
+    """
+    Error in the network protocol
+    """
+    NETWORK_PROTOCOL: int = 9,
+
+    """
+    Error while calling a system command
+    """
+    SYSTEM_COMMAND: int = 10,
+
+    """
+    Error with the database engine
+    """
+    DATABASE: int = 11,
+
+    """
+    Badly formatted URI
+    """
+    URI_SYNTAX: int = 12,
+
+    """
+    Inexistent file
+    """
+    INEXISTENT_FILE: int = 13,
+
+    """
+    Cannot write to file
+    """
+    CANNOT_WRITE_FILE: int = 14,
+
+    """
+    Bad file format
+    """
+    BAD_FILE_FORMAT: int = 15,
+
+    """
+    Timeout
+    """
+    TIMEOUT: int = 16,
+
+    """
+    Unknown resource
+    """
+    UNKNOWN_RESOURCE: int = 17,
+
+    """
+    Incompatible version of the database
+    """
+    INCOMPATIBLE_DATABASE_VERSION: int = 18,
+
+    """
+    The file storage is full
+    """
+    FULL_STORAGE: int = 19,
+
+    """
+    Corrupted file (e.g. inconsistent MD5 hash)
+    """
+    CORRUPTED_FILE: int = 20,
+
+    """
+    Inexistent tag
+    """
+    INEXISTENT_TAG: int = 21,
+
+    """
+    Cannot modify a read-only data structure
+    """
+    READ_ONLY: int = 22,
+
+    """
+    Incompatible format of the images
+    """
+    INCOMPATIBLE_IMAGE_FORMAT: int = 23,
+
+    """
+    Incompatible size of the images
+    """
+    INCOMPATIBLE_IMAGE_SIZE: int = 24,
+
+    """
+    Error while using a shared library (plugin)
+    """
+    SHARED_LIBRARY: int = 25,
+
+    """
+    Plugin invoking an unknown service
+    """
+    UNKNOWN_PLUGIN_SERVICE: int = 26,
+
+    """
+    Unknown DICOM tag
+    """
+    UNKNOWN_DICOM_TAG: int = 27,
+
+    """
+    Cannot parse a JSON document
+    """
+    BAD_JSON: int = 28,
+
+    """
+    Bad credentials were provided to an HTTP request
+    """
+    UNAUTHORIZED: int = 29,
+
+    """
+    Badly formatted font file
+    """
+    BAD_FONT: int = 30,
+
+    """
+    The plugin implementing a custom database back-end does not fulfill the proper interface
+    """
+    DATABASE_PLUGIN: int = 31,
+
+    """
+    Error in the plugin implementing a custom storage area
+    """
+    STORAGE_AREA_PLUGIN: int = 32,
+
+    """
+    The request is empty
+    """
+    EMPTY_REQUEST: int = 33,
+
+    """
+    Cannot send a response which is acceptable according to the Accept HTTP header
+    """
+    NOT_ACCEPTABLE: int = 34,
+
+    """
+    Cannot handle a NULL pointer
+    """
+    NULL_POINTER: int = 35,
+
+    """
+    The database is currently not available (probably a transient situation)
+    """
+    DATABASE_UNAVAILABLE: int = 36,
+
+    """
+    This job was canceled
+    """
+    CANCELED_JOB: int = 37,
+
+    """
+    Geometry error encountered in Stone
+    """
+    BAD_GEOMETRY: int = 38,
+
+    """
+    Cannot initialize SSL encryption, check out your certificates
+    """
+    SSL_INITIALIZATION: int = 39,
+
+    """
+    Calling a function that has been removed from the Orthanc Framework
+    """
+    DISCONTINUED_ABI: int = 40,
+
+    """
+    Incorrect range request
+    """
+    BAD_RANGE: int = 41,
+
+    """
+    Database could not serialize access due to concurrent update, the transaction should be retried
+    """
+    DATABASE_CANNOT_SERIALIZE: int = 42,
+
+    """
+    A bad revision number was provided, which might indicate conflict between multiple writers
+    """
+    REVISION: int = 43,
+
+    """
+    SQLite: The database is not opened
+    """
+    SQLITE_NOT_OPENED: int = 1000,
+
+    """
+    SQLite: Connection is already open
+    """
+    SQLITE_ALREADY_OPENED: int = 1001,
+
+    """
+    SQLite: Unable to open the database
+    """
+    SQLITE_CANNOT_OPEN: int = 1002,
+
+    """
+    SQLite: This cached statement is already being referred to
+    """
+    SQLITE_STATEMENT_ALREADY_USED: int = 1003,
+
+    """
+    SQLite: Cannot execute a command
+    """
+    SQLITE_EXECUTE: int = 1004,
+
+    """
+    SQLite: Rolling back a nonexistent transaction (have you called Begin()?)
+    """
+    SQLITE_ROLLBACK_WITHOUT_TRANSACTION: int = 1005,
+
+    """
+    SQLite: Committing a nonexistent transaction
+    """
+    SQLITE_COMMIT_WITHOUT_TRANSACTION: int = 1006,
+
+    """
+    SQLite: Unable to register a function
+    """
+    SQLITE_REGISTER_FUNCTION: int = 1007,
+
+    """
+    SQLite: Unable to flush the database
+    """
+    SQLITE_FLUSH: int = 1008,
+
+    """
+    SQLite: Cannot run a cached statement
+    """
+    SQLITE_CANNOT_RUN: int = 1009,
+
+    """
+    SQLite: Cannot step over a cached statement
+    """
+    SQLITE_CANNOT_STEP: int = 1010,
+
+    """
+    SQLite: Bing a value while out of range (serious error)
+    """
+    SQLITE_BIND_OUT_OF_RANGE: int = 1011,
+
+    """
+    SQLite: Cannot prepare a cached statement
+    """
+    SQLITE_PREPARE_STATEMENT: int = 1012,
+
+    """
+    SQLite: Beginning the same transaction twice
+    """
+    SQLITE_TRANSACTION_ALREADY_STARTED: int = 1013,
+
+    """
+    SQLite: Failure when committing the transaction
+    """
+    SQLITE_TRANSACTION_COMMIT: int = 1014,
+
+    """
+    SQLite: Cannot start a transaction
+    """
+    SQLITE_TRANSACTION_BEGIN: int = 1015,
+
+    """
+    The directory to be created is already occupied by a regular file
+    """
+    DIRECTORY_OVER_FILE: int = 2000,
+
+    """
+    Unable to create a subdirectory or a file in the file storage
+    """
+    FILE_STORAGE_CANNOT_WRITE: int = 2001,
+
+    """
+    The specified path does not point to a directory
+    """
+    DIRECTORY_EXPECTED: int = 2002,
+
+    """
+    The TCP port of the HTTP server is privileged or already in use
+    """
+    HTTP_PORT_IN_USE: int = 2003,
+
+    """
+    The TCP port of the DICOM server is privileged or already in use
+    """
+    DICOM_PORT_IN_USE: int = 2004,
+
+    """
+    This HTTP status is not allowed in a REST API
+    """
+    BAD_HTTP_STATUS_IN_REST: int = 2005,
+
+    """
+    The specified path does not point to a regular file
+    """
+    REGULAR_FILE_EXPECTED: int = 2006,
+
+    """
+    Unable to get the path to the executable
+    """
+    PATH_TO_EXECUTABLE: int = 2007,
+
+    """
+    Cannot create a directory
+    """
+    MAKE_DIRECTORY: int = 2008,
+
+    """
+    An application entity title (AET) cannot be empty or be longer than 16 characters
+    """
+    BAD_APPLICATION_ENTITY_TITLE: int = 2009,
+
+    """
+    No request handler factory for DICOM C-FIND SCP
+    """
+    NO_CFIND_HANDLER: int = 2010,
+
+    """
+    No request handler factory for DICOM C-MOVE SCP
+    """
+    NO_CMOVE_HANDLER: int = 2011,
+
+    """
+    No request handler factory for DICOM C-STORE SCP
+    """
+    NO_CSTORE_HANDLER: int = 2012,
+
+    """
+    No application entity filter
+    """
+    NO_APPLICATION_ENTITY_FILTER: int = 2013,
+
+    """
+    DicomUserConnection: Unable to find the SOP class and instance
+    """
+    NO_SOP_CLASS_OR_INSTANCE: int = 2014,
+
+    """
+    DicomUserConnection: No acceptable presentation context for modality
+    """
+    NO_PRESENTATION_CONTEXT: int = 2015,
+
+    """
+    DicomUserConnection: The C-FIND command is not supported by the remote SCP
+    """
+    DICOM_FIND_UNAVAILABLE: int = 2016,
+
+    """
+    DicomUserConnection: The C-MOVE command is not supported by the remote SCP
+    """
+    DICOM_MOVE_UNAVAILABLE: int = 2017,
+
+    """
+    Cannot store an instance
+    """
+    CANNOT_STORE_INSTANCE: int = 2018,
+
+    """
+    Only string values are supported when creating DICOM instances
+    """
+    CREATE_DICOM_NOT_STRING: int = 2019,
+
+    """
+    Trying to override a value inherited from a parent module
+    """
+    CREATE_DICOM_OVERRIDE_TAG: int = 2020,
+
+    """
+    Use \"Content\" to inject an image into a new DICOM instance
+    """
+    CREATE_DICOM_USE_CONTENT: int = 2021,
+
+    """
+    No payload is present for one instance in the series
+    """
+    CREATE_DICOM_NO_PAYLOAD: int = 2022,
+
+    """
+    The payload of the DICOM instance must be specified according to Data URI scheme
+    """
+    CREATE_DICOM_USE_DATA_URI_SCHEME: int = 2023,
+
+    """
+    Trying to attach a new DICOM instance to an inexistent resource
+    """
+    CREATE_DICOM_BAD_PARENT: int = 2024,
+
+    """
+    Trying to attach a new DICOM instance to an instance (must be a series, study or patient)
+    """
+    CREATE_DICOM_PARENT_IS_INSTANCE: int = 2025,
+
+    """
+    Unable to get the encoding of the parent resource
+    """
+    CREATE_DICOM_PARENT_ENCODING: int = 2026,
+
+    """
+    Unknown modality
+    """
+    UNKNOWN_MODALITY: int = 2027,
+
+    """
+    Bad ordering of filters in a job
+    """
+    BAD_JOB_ORDERING: int = 2028,
+
+    """
+    Cannot convert the given JSON object to a Lua table
+    """
+    JSON_TO_LUA_TABLE: int = 2029,
+
+    """
+    Cannot create the Lua context
+    """
+    CANNOT_CREATE_LUA: int = 2030,
+
+    """
+    Cannot execute a Lua command
+    """
+    CANNOT_EXECUTE_LUA: int = 2031,
+
+    """
+    Arguments cannot be pushed after the Lua function is executed
+    """
+    LUA_ALREADY_EXECUTED: int = 2032,
+
+    """
+    The Lua function does not give the expected number of outputs
+    """
+    LUA_BAD_OUTPUT: int = 2033,
+
+    """
+    The Lua function is not a predicate (only true/false outputs allowed)
+    """
+    NOT_LUA_PREDICATE: int = 2034,
+
+    """
+    The Lua function does not return a string
+    """
+    LUA_RETURNS_NO_STRING: int = 2035,
+
+    """
+    Another plugin has already registered a custom storage area
+    """
+    STORAGE_AREA_ALREADY_REGISTERED: int = 2036,
+
+    """
+    Another plugin has already registered a custom database back-end
+    """
+    DATABASE_BACKEND_ALREADY_REGISTERED: int = 2037,
+
+    """
+    Plugin trying to call the database during its initialization
+    """
+    DATABASE_NOT_INITIALIZED: int = 2038,
+
+    """
+    Orthanc has been built without SSL support
+    """
+    SSL_DISABLED: int = 2039,
+
+    """
+    Unable to order the slices of the series
+    """
+    CANNOT_ORDER_SLICES: int = 2040,
+
+    """
+    No request handler factory for DICOM C-Find Modality SCP
+    """
+    NO_WORKLIST_HANDLER: int = 2041,
+
+    """
+    Cannot override the value of a tag that already exists
+    """
+    ALREADY_EXISTING_TAG: int = 2042,
+
+    """
+    No request handler factory for DICOM N-ACTION SCP (storage commitment)
+    """
+    NO_STORAGE_COMMITMENT_HANDLER: int = 2043,
+
+    """
+    No request handler factory for DICOM C-GET SCP
+    """
+    NO_CGET_HANDLER: int = 2044,
+
+    """
+    Unsupported media type
+    """
+    UNSUPPORTED_MEDIA_TYPE: int = 3000,
+
+class HttpMethod(enum.Enum):
+    """
+    The various HTTP methods for a REST call.
+    """
+
+    """
+    GET request
+    """
+    GET: int = 1,
+
+    """
+    POST request
+    """
+    POST: int = 2,
+
+    """
+    PUT request
+    """
+    PUT: int = 3,
+
+    """
+    DELETE request
+    """
+    DELETE: int = 4,
+
+class IdentifierConstraint(enum.Enum):
+    """
+    The constraints on the DICOM identifiers that must be supported by the database plugins.
+    """
+
+    """
+    Equal
+    """
+    EQUAL: int = 1,
+
+    """
+    Less or equal
+    """
+    SMALLER_OR_EQUAL: int = 2,
+
+    """
+    More or equal
+    """
+    GREATER_OR_EQUAL: int = 3,
+
+    """
+    Case-sensitive wildcard matching (with * and ?)
+    """
+    WILDCARD: int = 4,
+
+class ImageFormat(enum.Enum):
+    """
+    The image formats that are supported by the Orthanc core.
+    """
+
+    """
+    Image compressed using PNG
+    """
+    PNG: int = 0,
+
+    """
+    Image compressed using JPEG
+    """
+    JPEG: int = 1,
+
+    """
+    Image compressed using DICOM
+    """
+    DICOM: int = 2,
+
+class InstanceOrigin(enum.Enum):
+    """
+    The origin of a DICOM instance that has been received by Orthanc.
+    """
+
+    """
+    Unknown origin
+    """
+    UNKNOWN: int = 1,
+
+    """
+    Instance received through DICOM protocol
+    """
+    DICOM_PROTOCOL: int = 2,
+
+    """
+    Instance received through REST API of Orthanc
+    """
+    REST_API: int = 3,
+
+    """
+    Instance added to Orthanc by a plugin
+    """
+    PLUGIN: int = 4,
+
+    """
+    Instance added to Orthanc by a Lua script
+    """
+    LUA: int = 5,
+
+    """
+    Instance received through WebDAV (new in 1.8.0)
+    """
+    WEB_DAV: int = 6,
+
+class JobStepStatus(enum.Enum):
+    """
+    The possible status for one single step of a job.
+    """
+
+    """
+    The job has successfully executed all its steps
+    """
+    SUCCESS: int = 1,
+
+    """
+    The job has failed while executing this step
+    """
+    FAILURE: int = 2,
+
+    """
+    The job has still data to process after this step
+    """
+    CONTINUE: int = 3,
+
+class JobStopReason(enum.Enum):
+    """
+    Explains why the job should stop and release the resources it has allocated. This is especially important to disambiguate between the "paused" condition and the "final" conditions (success, failure, or canceled).
+    """
+
+    """
+    The job has succeeded
+    """
+    SUCCESS: int = 1,
+
+    """
+    The job was paused, and will be resumed later
+    """
+    PAUSED: int = 2,
+
+    """
+    The job has failed, and might be resubmitted later
+    """
+    FAILURE: int = 3,
+
+    """
+    The job was canceled, and might be resubmitted later
+    """
+    CANCELED: int = 4,
+
+class MetricsType(enum.Enum):
+    """
+    The available types of metrics.
+    """
+
+    """
+    Default metrics
+    """
+    DEFAULT: int = 0,
+
+    """
+    This metrics represents a time duration. Orthanc will keep the maximum value of the metrics over a sliding window of ten seconds, which is useful if the metrics is sampled frequently.
+    """
+    TIMER: int = 1,
+
+class PixelFormat(enum.Enum):
+    """
+    The memory layout of the pixels of an image.
+    """
+
+    """
+    Graylevel 8bpp image. The image is graylevel. Each pixel is unsigned and stored in one byte.
+    """
+    GRAYSCALE8: int = 1,
+
+    """
+    Graylevel, unsigned 16bpp image. The image is graylevel. Each pixel is unsigned and stored in two bytes.
+    """
+    GRAYSCALE16: int = 2,
+
+    """
+    Graylevel, signed 16bpp image. The image is graylevel. Each pixel is signed and stored in two bytes.
+    """
+    SIGNED_GRAYSCALE16: int = 3,
+
+    """
+    Color image in RGB24 format. This format describes a color image. The pixels are stored in 3 consecutive bytes. The memory layout is RGB.
+    """
+    RGB24: int = 4,
+
+    """
+    Color image in RGBA32 format. This format describes a color image. The pixels are stored in 4 consecutive bytes. The memory layout is RGBA.
+    """
+    RGBA32: int = 5,
+
+    """
+    Unknown pixel format
+    """
+    UNKNOWN: int = 6,
+
+    """
+    Color image in RGB48 format. This format describes a color image. The pixels are stored in 6 consecutive bytes. The memory layout is RRGGBB.
+    """
+    RGB48: int = 7,
+
+    """
+    Graylevel, unsigned 32bpp image. The image is graylevel. Each pixel is unsigned and stored in four bytes.
+    """
+    GRAYSCALE32: int = 8,
+
+    """
+    Graylevel, floating-point 32bpp image. The image is graylevel. Each pixel is floating-point and stored in four bytes.
+    """
+    FLOAT32: int = 9,
+
+    """
+    Color image in BGRA32 format. This format describes a color image. The pixels are stored in 4 consecutive bytes. The memory layout is BGRA.
+    """
+    BGRA32: int = 10,
+
+    """
+    Graylevel, unsigned 64bpp image. The image is graylevel. Each pixel is unsigned and stored in eight bytes.
+    """
+    GRAYSCALE64: int = 11,
+
+class ReceivedInstanceAction(enum.Enum):
+    """
+    The action to be taken after ReceivedInstanceCallback is triggered
+    """
+
+    """
+    Keep the instance as is
+    """
+    KEEP_AS_IS: int = 1,
+
+    """
+    Modify the instance
+    """
+    MODIFY: int = 2,
+
+    """
+    Discard the instance
+    """
+    DISCARD: int = 3,
+
+class ResourceType(enum.Enum):
+    """
+    The supported types of DICOM resources.
+    """
+
+    """
+    Patient
+    """
+    PATIENT: int = 0,
+
+    """
+    Study
+    """
+    STUDY: int = 1,
+
+    """
+    Series
+    """
+    SERIES: int = 2,
+
+    """
+    Instance
+    """
+    INSTANCE: int = 3,
+
+    """
+    Unavailable resource type
+    """
+    NONE: int = 4,
+
+class StorageCommitmentFailureReason(enum.Enum):
+    """
+    The available values for the Failure Reason (0008,1197) during storage commitment. http://dicom.nema.org/medical/dicom/2019e/output/chtml/part03/sect_C.14.html#sect_C.14.1.1
+    """
+
+    """
+    Success: The DICOM instance is properly stored in the SCP
+    """
+    SUCCESS: int = 0,
+
+    """
+    0110H: A general failure in processing the operation was encountered
+    """
+    PROCESSING_FAILURE: int = 1,
+
+    """
+    0112H: One or more of the elements in the Referenced SOP Instance Sequence was not available
+    """
+    NO_SUCH_OBJECT_INSTANCE: int = 2,
+
+    """
+    0213H: The SCP does not currently have enough resources to store the requested SOP Instance(s)
+    """
+    RESOURCE_LIMITATION: int = 3,
+
+    """
+    0122H: Storage Commitment has been requested for a SOP Instance with a SOP Class that is not supported by the SCP
+    """
+    REFERENCED_SOPCLASS_NOT_SUPPORTED: int = 4,
+
+    """
+    0119H: The SOP Class of an element in the Referenced SOP Instance Sequence did not correspond to the SOP class registered for this SOP Instance at the SCP
+    """
+    CLASS_INSTANCE_CONFLICT: int = 5,
+
+    """
+    0131H: The Transaction UID of the Storage Commitment Request is already in use
+    """
+    DUPLICATE_TRANSACTION_UID: int = 6,
+
+class ValueRepresentation(enum.Enum):
+    """
+    The value representations present in the DICOM standard (version 2013).
+    """
+
+    """
+    Application Entity
+    """
+    AE: int = 1,
+
+    """
+    Age String
+    """
+    AS: int = 2,
+
+    """
+    Attribute Tag
+    """
+    AT: int = 3,
+
+    """
+    Code String
+    """
+    CS: int = 4,
+
+    """
+    Date
+    """
+    DA: int = 5,
+
+    """
+    Decimal String
+    """
+    DS: int = 6,
+
+    """
+    Date Time
+    """
+    DT: int = 7,
+
+    """
+    Floating Point Double
+    """
+    FD: int = 8,
+
+    """
+    Floating Point Single
+    """
+    FL: int = 9,
+
+    """
+    Integer String
+    """
+    IS: int = 10,
+
+    """
+    Long String
+    """
+    LO: int = 11,
+
+    """
+    Long Text
+    """
+    LT: int = 12,
+
+    """
+    Other Byte String
+    """
+    OB: int = 13,
+
+    """
+    Other Float String
+    """
+    OF: int = 14,
+
+    """
+    Other Word String
+    """
+    OW: int = 15,
+
+    """
+    Person Name
+    """
+    PN: int = 16,
+
+    """
+    Short String
+    """
+    SH: int = 17,
+
+    """
+    Signed Long
+    """
+    SL: int = 18,
+
+    """
+    Sequence of Items
+    """
+    SQ: int = 19,
+
+    """
+    Signed Short
+    """
+    SS: int = 20,
+
+    """
+    Short Text
+    """
+    ST: int = 21,
+
+    """
+    Time
+    """
+    TM: int = 22,
+
+    """
+    Unique Identifier (UID)
+    """
+    UI: int = 23,
+
+    """
+    Unsigned Long
+    """
+    UL: int = 24,
+
+    """
+    Unknown
+    """
+    UN: int = 25,
+
+    """
+    Unsigned Short
+    """
+    US: int = 26,
+
+    """
+    Unlimited Text
+    """
+    UT: int = 27,
+
+
+# This function returns the MIME type of a file by inspecting its extension
+def AutodetectMimeType(path: str) -> str:
+    """
+    This function returns the MIME type of a file by inspecting its extension.
+
+    Args:
+      path (str): Path to the file.
+
+    Returns:
+      str: The MIME type. This is a statically-allocated string, do not free it.
+    """
+    ...
+# This function compresses or decompresses a buffer, using the version of the zlib library that is used by the Orthanc core
+def BufferCompression(source: bytes, compression: CompressionType, uncompress: int) -> bytes:
+    """
+    This function compresses or decompresses a buffer, using the version of the zlib library that is used by the Orthanc core.
+
+    Args:
+      source (bytes): The source buffer.
+      compression (CompressionType): The compression algorithm.
+      uncompress (int): If set to "0", the buffer must be compressed. If set to "1", the buffer must be uncompressed.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# This function checks whether the version of the Orthanc server running this plugin, is above the version of the current Orthanc SDK header
+def CheckVersion() -> int:
+    """
+    This function checks whether the version of the Orthanc server running this plugin, is above the version of the current Orthanc SDK header. This guarantees that the plugin is compatible with the hosting Orthanc (i.e. it will not call unavailable services). The result of this function should always be checked in the OrthancPluginInitialize() entry point of the plugin.
+
+    Returns:
+      int: 1 if and only if the versions are compatible. If the result is 0, the initialization of the plugin should fail.
+    """
+    ...
+# This function checks whether the version of the Orthanc server running this plugin, is above the given version
+def CheckVersionAdvanced(expected_major: int, expected_minor: int, expected_revision: int) -> int:
+    """
+    This function checks whether the version of the Orthanc server running this plugin, is above the given version. Contrarily to OrthancPluginCheckVersion(), it is up to the developer of the plugin to make sure that all the Orthanc SDK services called by the plugin are actually implemented in the given version of Orthanc.
+
+    Args:
+      expected_major (int): Expected major version.
+      expected_minor (int): Expected minor version.
+      expected_revision (int): Expected revision.
+
+    Returns:
+      int: 1 if and only if the versions are compatible. If the result is 0, the initialization of the plugin should fail.
+    """
+    ...
+# This function compresses the given memory buffer containing an image using the JPEG specification, and stores the result of the compression into a newly allocated memory buffer
+def CompressJpegImage(format: PixelFormat, width: int, height: int, pitch: int, buffer: bytes, quality: int) -> bytes:
+    """
+    This function compresses the given memory buffer containing an image using the JPEG specification, and stores the result of the compression into a newly allocated memory buffer.
+
+    Args:
+      format (PixelFormat): The memory layout of the uncompressed image.
+      width (int): The width of the image.
+      height (int): The height of the image.
+      pitch (int): The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).
+      buffer (bytes): The memory buffer containing the uncompressed image.
+      quality (int): The quality of the JPEG encoding, between 1 (worst quality, best compression) and 100 (best quality, worst compression).
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# This function compresses the given memory buffer containing an image using the PNG specification, and stores the result of the compression into a newly allocated memory buffer
+def CompressPngImage(format: PixelFormat, width: int, height: int, pitch: int, buffer: bytes) -> bytes:
+    """
+    This function compresses the given memory buffer containing an image using the PNG specification, and stores the result of the compression into a newly allocated memory buffer.
+
+    Args:
+      format (PixelFormat): The memory layout of the uncompressed image.
+      width (int): The width of the image.
+      height (int): The height of the image.
+      pitch (int): The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).
+      buffer (bytes): The memory buffer containing the uncompressed image.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# This functions computes the MD5 cryptographic hash of the given memory buffer
+def ComputeMd5(buffer: bytes) -> str:
+    """
+    This functions computes the MD5 cryptographic hash of the given memory buffer.
+
+    Args:
+      buffer (bytes): The source memory buffer.
+
+    Returns:
+      str: The NULL value in case of error, or a string containing the cryptographic hash. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# This functions computes the SHA-1 cryptographic hash of the given memory buffer
+def ComputeSha1(buffer: bytes) -> str:
+    """
+    This functions computes the SHA-1 cryptographic hash of the given memory buffer.
+
+    Args:
+      buffer (bytes): The source memory buffer.
+
+    Returns:
+      str: The NULL value in case of error, or a string containing the cryptographic hash. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# This function takes as input a string containing a JSON file describing the content of a DICOM instance
+def CreateDicom(json: str, pixel_data: Image, flags: CreateDicomFlags) -> bytes:
+    """
+    This function takes as input a string containing a JSON file describing the content of a DICOM instance. As an output, it writes the corresponding DICOM instance to a newly allocated memory buffer. Additionally, an image to be encoded within the DICOM instance can also be provided.
+    Private tags will be associated with the private creator whose value is specified in the "DefaultPrivateCreator" configuration option of Orthanc. The function OrthancPluginCreateDicom2() can be used if another private creator must be used to create this instance.
+
+    Args:
+      json (str): The input JSON file.
+      pixel_data (Image): The image. Can be NULL, if the pixel data is encoded inside the JSON with the data URI scheme.
+      flags (CreateDicomFlags): Flags governing the output.
+
+    Returns:
+      bytes: 0 if success, other value if error.
+    """
+    ...
+# This function takes as input a string containing a JSON file describing the content of a DICOM instance
+def CreateDicom2(json: str, pixel_data: Image, flags: CreateDicomFlags, private_creator: str) -> bytes:
+    """
+    This function takes as input a string containing a JSON file describing the content of a DICOM instance. As an output, it writes the corresponding DICOM instance to a newly allocated memory buffer. Additionally, an image to be encoded within the DICOM instance can also be provided.
+    Contrarily to the function OrthancPluginCreateDicom(), this function can be explicitly provided with a private creator.
+
+    Args:
+      json (str): The input JSON file.
+      pixel_data (Image): The image. Can be NULL, if the pixel data is encoded inside the JSON with the data URI scheme.
+      flags (CreateDicomFlags): Flags governing the output.
+      private_creator (str): The private creator to be used for the private DICOM tags. Check out the global configuration option "Dictionary" of Orthanc.
+
+    Returns:
+      bytes: 0 if success, other value if error.
+    """
+    ...
+# This function parses a memory buffer that contains a DICOM file
+def CreateDicomInstance(buffer: bytes) -> DicomInstance:
+    """
+    This function parses a memory buffer that contains a DICOM file. The function returns a new pointer to a data structure that is managed by the Orthanc core.
+
+    Args:
+      buffer (bytes): The memory buffer containing the DICOM instance.
+
+    Returns:
+      DicomInstance: The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().
+    """
+    ...
+# This function creates a "matcher" object that can be used to check whether a DICOM instance matches a C-Find query
+def CreateFindMatcher(query: bytes) -> FindMatcher:
+    """
+    This function creates a "matcher" object that can be used to check whether a DICOM instance matches a C-Find query. The C-Find query must be expressed as a DICOM buffer.
+
+    Args:
+      query (bytes): The C-Find DICOM query.
+
+    Returns:
+      FindMatcher: The newly allocated matcher. It must be freed with OrthancPluginFreeFindMatcher().
+    """
+    ...
+# This function creates an image of given size and format
+def CreateImage(format: PixelFormat, width: int, height: int) -> Image:
+    """
+    This function creates an image of given size and format.
+
+    Args:
+      format (PixelFormat): The format of the pixels.
+      width (int): The width of the image.
+      height (int): The height of the image.
+
+    Returns:
+      Image: The newly allocated image. It must be freed with OrthancPluginFreeImage().
+    """
+    ...
+# This function decodes one frame of a DICOM image that is stored in a memory buffer
+def DecodeDicomImage(buffer: bytes, frame_index: int) -> Image:
+    """
+    This function decodes one frame of a DICOM image that is stored in a memory buffer. This function will give the same result as OrthancPluginUncompressImage() for single-frame DICOM images.
+
+    Args:
+      buffer (bytes): Pointer to a memory buffer containing the DICOM image.
+      frame_index (int): The index of the frame of interest in a multi-frame image.
+
+    Returns:
+      Image: The uncompressed image. It must be freed with OrthancPluginFreeImage().
+    """
+    ...
+# This function takes as input a memory buffer containing a DICOM file, and outputs a JSON string representing the tags of this DICOM file
+def DicomBufferToJson(buffer: bytes, format: DicomToJsonFormat, flags: DicomToJsonFlags, max_string_length: int) -> str:
+    """
+    This function takes as input a memory buffer containing a DICOM file, and outputs a JSON string representing the tags of this DICOM file.
+
+    Args:
+      buffer (bytes): The memory buffer containing the DICOM file.
+      format (DicomToJsonFormat): The output format.
+      flags (DicomToJsonFlags): Flags governing the output.
+      max_string_length (int): The maximum length of a field. Too long fields will be output as "null". The 0 value means no maximum length.
+
+    Returns:
+      str: The NULL value if the case of an error, or the JSON string. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# This function formats a DICOM instance that is stored in Orthanc, and outputs a JSON string representing the tags of this DICOM instance
+def DicomInstanceToJson(instance_id: str, format: DicomToJsonFormat, flags: DicomToJsonFlags, max_string_length: int) -> str:
+    """
+    This function formats a DICOM instance that is stored in Orthanc, and outputs a JSON string representing the tags of this DICOM instance.
+
+    Args:
+      instance_id (str): The Orthanc identifier of the instance.
+      format (DicomToJsonFormat): The output format.
+      flags (DicomToJsonFlags): Flags governing the output.
+      max_string_length (int): The maximum length of a field. Too long fields will be output as "null". The 0 value means no maximum length.
+
+    Returns:
+      str: The NULL value if the case of an error, or the JSON string. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Add JavaScript code to customize the default behavior of Orthanc Explorer
+def ExtendOrthancExplorer(javascript: str) -> None:
+    """
+    Add JavaScript code to customize the default behavior of Orthanc Explorer. This can for instance be used to add new buttons.
+
+    Args:
+      javascript (str): The custom JavaScript code.
+    """
+    ...
+# This function generates a token that can be set in the HTTP header "Authorization" so as to grant full access to the REST API of Orthanc using an external HTTP client
+def GenerateRestApiAuthorizationToken() -> str:
+    """
+    This function generates a token that can be set in the HTTP header "Authorization" so as to grant full access to the REST API of Orthanc using an external HTTP client. Using this function avoids the need of adding a separate user in the "RegisteredUsers" configuration of Orthanc, which eases deployments.
+    This feature is notably useful in multiprocess scenarios, where a subprocess created by a plugin has no access to the "OrthancPluginContext", and thus cannot call "OrthancPluginRestApi[Get|Post|Put|Delete]()".
+    This situation is frequently encountered in Python plugins, where the "multiprocessing" package can be used to bypass the Global Interpreter Lock (GIL) and thus to improve performance and concurrency.
+
+    Returns:
+      str: The authorization token, or NULL value in the case of an error. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Generate a random GUID/UUID (globally unique identifier)
+def GenerateUuid() -> str:
+    """
+    Generate a random GUID/UUID (globally unique identifier).
+
+    Returns:
+      str: NULL in the case of an error, or a newly allocated string containing the UUID. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Get the value of one of the command-line arguments that were used to launch Orthanc
+def GetCommandLineArgument(argument: int) -> str:
+    """
+    Get the value of one of the command-line arguments that were used to launch Orthanc. The number of available arguments can be retrieved by OrthancPluginGetCommandLineArgumentsCount().
+
+    Args:
+      argument (int): The index of the argument.
+
+    Returns:
+      str: The value of the argument, or NULL in the case of an error. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Retrieve the number of command-line arguments that were used to launch Orthanc
+def GetCommandLineArgumentsCount() -> int:
+    """
+    Retrieve the number of command-line arguments that were used to launch Orthanc.
+
+    Returns:
+      int: The number of arguments.
+    """
+    ...
+# This function returns the content of the configuration that is used by Orthanc, formatted as a JSON string
+def GetConfiguration() -> str:
+    """
+    This function returns the content of the configuration that is used by Orthanc, formatted as a JSON string.
+
+    Returns:
+      str: NULL in the case of an error, or a newly allocated string containing the configuration. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# This function returns the path to the configuration file(s) that was specified when starting Orthanc
+def GetConfigurationPath() -> str:
+    """
+    This function returns the path to the configuration file(s) that was specified when starting Orthanc. Since version 0.9.1, this path can refer to a folder that stores a set of configuration files. This function is deprecated in favor of OrthancPluginGetConfiguration().
+
+    Returns:
+      str: NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Retrieve a DICOM instance using its Orthanc identifier
+def GetDicomForInstance(instance_id: str) -> bytes:
+    """
+    Retrieve a DICOM instance using its Orthanc identifier. The DICOM file is stored into a newly allocated memory buffer.
+
+    Args:
+      instance_id (str): The Orthanc identifier of the DICOM instance of interest.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# This function returns the description of a given error code
+def GetErrorDescription(error: ErrorCode) -> str:
+    """
+    This function returns the description of a given error code.
+
+    Args:
+      error (ErrorCode): The error code of interest.
+
+    Returns:
+      str: The error description. This is a statically-allocated string, do not free it.
+    """
+    ...
+# Retrieve the expected version of the database schema
+def GetExpectedDatabaseVersion() -> int:
+    """
+    Retrieve the expected version of the database schema.
+
+    Returns:
+      int: The version.
+    """
+    ...
+# This function returns the name of a font that is built in the Orthanc core
+def GetFontName(font_index: int) -> str:
+    """
+    This function returns the name of a font that is built in the Orthanc core.
+
+    Args:
+      font_index (int): The index of the font. This value must be less than OrthancPluginGetFontsCount().
+
+    Returns:
+      str: The font name. This is a statically-allocated string, do not free it.
+    """
+    ...
+# This function returns the size of a font that is built in the Orthanc core
+def GetFontSize(font_index: int) -> int:
+    """
+    This function returns the size of a font that is built in the Orthanc core.
+
+    Args:
+      font_index (int): The index of the font. This value must be less than OrthancPluginGetFontsCount().
+
+    Returns:
+      int: The font size.
+    """
+    ...
+# This function returns the number of fonts that are built in the Orthanc core
+def GetFontsCount() -> int:
+    """
+    This function returns the number of fonts that are built in the Orthanc core. These fonts can be used to draw texts on images through OrthancPluginDrawText().
+
+    Returns:
+      int: The number of fonts.
+    """
+    ...
+# Get the value of a global property that is stored in the Orthanc database
+def GetGlobalProperty(property: int, default_value: str) -> str:
+    """
+    Get the value of a global property that is stored in the Orthanc database. Global properties whose index is below 1024 are reserved by Orthanc.
+
+    Args:
+      property (int): The global property of interest.
+      default_value (str): The value to return, if the global property is unset.
+
+    Returns:
+      str: The value of the global property, or NULL in the case of an error. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# This function returns the path to the directory containing the Orthanc executable
+def GetOrthancDirectory() -> str:
+    """
+    This function returns the path to the directory containing the Orthanc executable.
+
+    Returns:
+      str: NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# This function returns the path to the Orthanc executable
+def GetOrthancPath() -> str:
+    """
+    This function returns the path to the Orthanc executable.
+
+    Returns:
+      str: NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# This function returns the parameters of the Orthanc peers that are known to the Orthanc server hosting the plugin
+def GetPeers() -> Peers:
+    """
+    This function returns the parameters of the Orthanc peers that are known to the Orthanc server hosting the plugin.
+
+    Returns:
+      Peers: NULL if error, or a newly allocated opaque data structure containing the peers. This structure must be freed with OrthancPluginFreePeers().
+    """
+    ...
+# This function makes a lookup to the dictionary of DICOM tags that are known to Orthanc, and returns the symbolic name of a DICOM tag
+def GetTagName(group: int, element: int, private_creator: str) -> str:
+    """
+    This function makes a lookup to the dictionary of DICOM tags that are known to Orthanc, and returns the symbolic name of a DICOM tag.
+
+    Args:
+      group (int): The group of the tag.
+      element (int): The element of the tag.
+      private_creator (str): For private tags, the name of the private creator (can be NULL).
+
+    Returns:
+      str: NULL in the case of an error, or a newly allocated string containing the path. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Make a HTTP DELETE call to the given URL
+def HttpDelete(url: str, username: str, password: str) -> None:
+    """
+    Make a HTTP DELETE call to the given URL. Favor OrthancPluginRestApiDelete() if calling the built-in REST API of the Orthanc instance that hosts this plugin.
+
+    Args:
+      url (str): The URL of interest.
+      username (str): The username (can be "NULL" if no password protection).
+      password (str): The password (can be "NULL" if no password protection).
+    """
+    ...
+# Make a HTTP GET call to the given URL
+def HttpGet(url: str, username: str, password: str) -> bytes:
+    """
+    Make a HTTP GET call to the given URL. The result to the query is stored into a newly allocated memory buffer. Favor OrthancPluginRestApiGet() if calling the built-in REST API of the Orthanc instance that hosts this plugin.
+
+    Args:
+      url (str): The URL of interest.
+      username (str): The username (can be "NULL" if no password protection).
+      password (str): The password (can be "NULL" if no password protection).
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Make a HTTP POST call to the given URL
+def HttpPost(url: str, body: bytes, username: str, password: str) -> bytes:
+    """
+    Make a HTTP POST call to the given URL. The result to the query is stored into a newly allocated memory buffer. Favor OrthancPluginRestApiPost() if calling the built-in REST API of the Orthanc instance that hosts this plugin.
+
+    Args:
+      url (str): The URL of interest.
+      body (bytes): The content of the body of the request.
+      username (str): The username (can be "NULL" if no password protection).
+      password (str): The password (can be "NULL" if no password protection).
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Make a HTTP PUT call to the given URL
+def HttpPut(url: str, body: bytes, username: str, password: str) -> bytes:
+    """
+    Make a HTTP PUT call to the given URL. The result to the query is stored into a newly allocated memory buffer. Favor OrthancPluginRestApiPut() if calling the built-in REST API of the Orthanc instance that hosts this plugin.
+
+    Args:
+      url (str): The URL of interest.
+      body (bytes): The content of the body of the request.
+      username (str): The username (can be "NULL" if no password protection).
+      password (str): The password (can be "NULL" if no password protection).
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Log an error message using the Orthanc logging system
+def LogError(message: str) -> None:
+    """
+    Log an error message using the Orthanc logging system.
+
+    Args:
+      message (str): The message to be logged.
+    """
+    ...
+# Log an information message using the Orthanc logging system
+def LogInfo(message: str) -> None:
+    """
+    Log an information message using the Orthanc logging system.
+
+    Args:
+      message (str): The message to be logged.
+    """
+    ...
+# Log a warning message using the Orthanc logging system
+def LogWarning(message: str) -> None:
+    """
+    Log a warning message using the Orthanc logging system.
+
+    Args:
+      message (str): The message to be logged.
+    """
+    ...
+# Look for an instance stored in Orthanc, using its SOP Instance UID tag (0x0008, 0x0018)
+def LookupInstance(sop_instance_u_i_d: str) -> str:
+    """
+    Look for an instance stored in Orthanc, using its SOP Instance UID tag (0x0008, 0x0018). This function uses the database index to run as fast as possible (it does not loop over all the stored instances).
+
+    Args:
+      sop_instance_u_i_d (str): The SOP Instance UID of interest.
+
+    Returns:
+      str: The NULL value if the instance is non-existent, or a string containing the Orthanc ID of the instance. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Look for a patient stored in Orthanc, using its Patient ID tag (0x0010, 0x0020)
+def LookupPatient(patient_i_d: str) -> str:
+    """
+    Look for a patient stored in Orthanc, using its Patient ID tag (0x0010, 0x0020). This function uses the database index to run as fast as possible (it does not loop over all the stored patients).
+
+    Args:
+      patient_i_d (str): The Patient ID of interest.
+
+    Returns:
+      str: The NULL value if the patient is non-existent, or a string containing the Orthanc ID of the patient. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Look for a series stored in Orthanc, using its Series Instance UID tag (0x0020, 0x000e)
+def LookupSeries(series_u_i_d: str) -> str:
+    """
+    Look for a series stored in Orthanc, using its Series Instance UID tag (0x0020, 0x000e). This function uses the database index to run as fast as possible (it does not loop over all the stored series).
+
+    Args:
+      series_u_i_d (str): The Series Instance UID of interest.
+
+    Returns:
+      str: The NULL value if the series is non-existent, or a string containing the Orthanc ID of the series. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Look for a study stored in Orthanc, using its Study Instance UID tag (0x0020, 0x000d)
+def LookupStudy(study_u_i_d: str) -> str:
+    """
+    Look for a study stored in Orthanc, using its Study Instance UID tag (0x0020, 0x000d). This function uses the database index to run as fast as possible (it does not loop over all the stored studies).
+
+    Args:
+      study_u_i_d (str): The Study Instance UID of interest.
+
+    Returns:
+      str: The NULL value if the study is non-existent, or a string containing the Orthanc ID of the study. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Look for a study stored in Orthanc, using its Accession Number tag (0x0008, 0x0050)
+def LookupStudyWithAccessionNumber(accession_number: str) -> str:
+    """
+    Look for a study stored in Orthanc, using its Accession Number tag (0x0008, 0x0050). This function uses the database index to run as fast as possible (it does not loop over all the stored studies).
+
+    Args:
+      accession_number (str): The Accession Number of interest.
+
+    Returns:
+      str: The NULL value if the study is non-existent, or a string containing the Orthanc ID of the study. This string must be freed by OrthancPluginFreeString().
+    """
+    ...
+# Read the content of a file on the filesystem, and returns it into a newly allocated memory buffer
+def ReadFile(path: str) -> bytes:
+    """
+    Read the content of a file on the filesystem, and returns it into a newly allocated memory buffer.
+
+    Args:
+      path (str): The path of the file to be read.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# This function declares a new public tag in the dictionary of DICOM tags that are known to Orthanc
+def RegisterDictionaryTag(group: int, element: int, vr: ValueRepresentation, name: str, min_multiplicity: int, max_multiplicity: int) -> None:
+    """
+    This function declares a new public tag in the dictionary of DICOM tags that are known to Orthanc. This function should be used in the OrthancPluginInitialize() callback.
+
+    Args:
+      group (int): The group of the tag.
+      element (int): The element of the tag.
+      vr (ValueRepresentation): The value representation of the tag.
+      name (str): The nickname of the tag.
+      min_multiplicity (int): The minimum multiplicity of the tag (must be above 0).
+      max_multiplicity (int): The maximum multiplicity of the tag. A value of 0 means an arbitrary multiplicity (""n"").
+    """
+    ...
+# This function declares a custom error code that can be generated by this plugin
+def RegisterErrorCode(code: int, http_status: int, message: str) -> None:
+    """
+    This function declares a custom error code that can be generated by this plugin. This declaration is used to enrich the body of the HTTP answer in the case of an error, and to set the proper HTTP status code.
+
+    Args:
+      code (int): The error code that is internal to this plugin.
+      http_status (int): The HTTP status corresponding to this error.
+      message (str): The description of the error.
+    """
+    ...
+# This function declares a new private tag in the dictionary of DICOM tags that are known to Orthanc
+def RegisterPrivateDictionaryTag(group: int, element: int, vr: ValueRepresentation, name: str, min_multiplicity: int, max_multiplicity: int, private_creator: str) -> None:
+    """
+    This function declares a new private tag in the dictionary of DICOM tags that are known to Orthanc. This function should be used in the OrthancPluginInitialize() callback.
+
+    Args:
+      group (int): The group of the tag.
+      element (int): The element of the tag.
+      vr (ValueRepresentation): The value representation of the tag.
+      name (str): The nickname of the tag.
+      min_multiplicity (int): The minimum multiplicity of the tag (must be above 0).
+      max_multiplicity (int): The maximum multiplicity of the tag. A value of 0 means an arbitrary multiplicity (""n"").
+      private_creator (str): The private creator of this private tag.
+    """
+    ...
+# Make a DELETE call to the built-in Orthanc REST API
+def RestApiDelete(uri: str) -> None:
+    """
+    Make a DELETE call to the built-in Orthanc REST API.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI to delete in the built-in Orthanc API.
+    """
+    ...
+# Make a DELETE call to the Orthanc REST API, after all the plugins are applied
+def RestApiDeleteAfterPlugins(uri: str) -> None:
+    """
+    Make a DELETE call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI to delete in the built-in Orthanc API.
+    """
+    ...
+# Make a GET call to the built-in Orthanc REST API
+def RestApiGet(uri: str) -> bytes:
+    """
+    Make a GET call to the built-in Orthanc REST API. The result to the query is stored into a newly allocated memory buffer.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI in the built-in Orthanc API.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Make a GET call to the Orthanc REST API, after all the plugins are applied
+def RestApiGetAfterPlugins(uri: str) -> bytes:
+    """
+    Make a GET call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin. The result to the query is stored into a newly allocated memory buffer.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI in the built-in Orthanc API.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Make a POST call to the built-in Orthanc REST API
+def RestApiPost(uri: str, body: bytes) -> bytes:
+    """
+    Make a POST call to the built-in Orthanc REST API. The result to the query is stored into a newly allocated memory buffer.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI in the built-in Orthanc API.
+      body (bytes): The body of the POST request.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Make a POST call to the Orthanc REST API, after all the plugins are applied
+def RestApiPostAfterPlugins(uri: str, body: bytes) -> bytes:
+    """
+    Make a POST call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin. The result to the query is stored into a newly allocated memory buffer.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI in the built-in Orthanc API.
+      body (bytes): The body of the POST request.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Make a PUT call to the built-in Orthanc REST API
+def RestApiPut(uri: str, body: bytes) -> bytes:
+    """
+    Make a PUT call to the built-in Orthanc REST API. The result to the query is stored into a newly allocated memory buffer.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI in the built-in Orthanc API.
+      body (bytes): The body of the PUT request.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Make a PUT call to the Orthanc REST API, after all the plugins are applied
+def RestApiPutAfterPlugins(uri: str, body: bytes) -> bytes:
+    """
+    Make a PUT call to the Orthanc REST API, after all the plugins are applied. In other words, if some plugin overrides or adds the called URI to the built-in Orthanc REST API, this call will return the result provided by this plugin. The result to the query is stored into a newly allocated memory buffer.
+    Remark: If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource.
+
+    Args:
+      uri (str): The URI in the built-in Orthanc API.
+      body (bytes): The body of the PUT request.
+
+    Returns:
+      bytes: 0 if success, or the error code if failure.
+    """
+    ...
+# Set a description for this plugin
+def SetDescription(description: str) -> None:
+    """
+    Set a description for this plugin. It is displayed in the "Plugins" page of Orthanc Explorer.
+
+    Args:
+      description (str): The description.
+    """
+    ...
+# Set the value of a global property into the Orthanc database
+def SetGlobalProperty(property: int, value: str) -> None:
+    """
+    Set the value of a global property into the Orthanc database. Setting a global property can be used by plugins to save their internal parameters. Plugins are only allowed to set properties whose index are above or equal to 1024 (properties below 1024 are read-only and reserved by Orthanc).
+
+    Args:
+      property (int): The global property of interest.
+      value (str): The value to be set in the global property.
+    """
+    ...
+# This function sets the value of a metrics to monitor the behavior of the plugin through tools such as Prometheus
+def SetMetricsValue(name: str, value: float, type: MetricsType) -> None:
+    """
+    This function sets the value of a metrics to monitor the behavior of the plugin through tools such as Prometheus. The values of all the metrics are stored within the Orthanc context.
+
+    Args:
+      name (str): The name of the metrics to be set.
+      value (float): The value of the metrics.
+      type (MetricsType): The type of the metrics. This parameter is only taken into consideration the first time this metrics is set.
+    """
+    ...
+# For plugins that come with a Web interface, this function declares the entry path where to find this interface
+def SetRootUri(uri: str) -> None:
+    """
+    For plugins that come with a Web interface, this function declares the entry path where to find this interface. This information is notably used in the "Plugins" page of Orthanc Explorer.
+
+    Args:
+      uri (str): The root URI for this plugin.
+    """
+    ...
+# This function parses a memory buffer that contains a DICOM file, then transcodes it to the given transfer syntax
+def TranscodeDicomInstance(buffer: bytes, transfer_syntax: str) -> DicomInstance:
+    """
+    This function parses a memory buffer that contains a DICOM file, then transcodes it to the given transfer syntax. The function returns a new pointer to a data structure that is managed by the Orthanc core.
+
+    Args:
+      buffer (bytes): The memory buffer containing the DICOM instance.
+      transfer_syntax (str): The transfer syntax UID for the transcoding.
+
+    Returns:
+      DicomInstance: The newly allocated DICOM instance. It must be freed with OrthancPluginFreeDicomInstance().
+    """
+    ...
+# This function decodes a compressed image from a memory buffer
+def UncompressImage(data: bytes, format: ImageFormat) -> Image:
+    """
+    This function decodes a compressed image from a memory buffer.
+
+    Args:
+      data (bytes): Pointer to a memory buffer containing the compressed image.
+      format (ImageFormat): The file format of the compressed image.
+
+    Returns:
+      Image: The uncompressed image. It must be freed with OrthancPluginFreeImage().
+    """
+    ...
+# Write the content of a memory buffer to the filesystem
+def WriteFile(path: str, data: bytes) -> None:
+    """
+    Write the content of a memory buffer to the filesystem.
+
+    Args:
+      path (str): The path of the file to be written.
+      data (bytes): The content of the memory buffer.
+    """
+    ...
+# Register a callback to monitor changes
+def RegisterOnChangeCallback(callback: typing.Callable[[ChangeType, ResourceType, str], None]) -> None:
+    """
+    Register a callback to monitor changes.
+
+    Args:
+      callback (typing.Callable[[ChangeType, ResourceType, str], None]): The callback function.
+    """
+    ...
+# Register a REST callback
+def RegisterRestCallback(path_regular_expression: str, callback: typing.Callable[[RestOutput, str], None]) -> None:
+    """
+    Register a REST callback.
+
+    Args:
+      path_regular_expression (str): Regular expression for the URI. May contain groups.
+      callback (typing.Callable[[RestOutput, str], None]): The callback function to handle the REST call.
+    """
+    ...
+
+
+class DicomInstance:
+    """
+    DICOM instance managed by the Orthanc core
+    """
+    ...
+
+    # This function returns the Application Entity Title (AET) of the DICOM modality from which a DICOM instance originates
+    def GetInstanceRemoteAet(self) -> str:
+        """
+        This function returns the Application Entity Title (AET) of the DICOM modality from which a DICOM instance originates.
+
+        Returns:
+          str: The AET if success, NULL if error.
+        """
+        ...
+    # This function returns the number of bytes of the given DICOM instance
+    def GetInstanceSize(self) -> int:
+        """
+        This function returns the number of bytes of the given DICOM instance.
+
+        Returns:
+          int: The size of the file, -1 in case of error.
+        """
+        ...
+    # This function returns a pointer to a newly created string containing a JSON file
+    def GetInstanceJson(self) -> str:
+        """
+        This function returns a pointer to a newly created string containing a JSON file. This JSON file encodes the tag hierarchy of the given DICOM instance.
+
+        Returns:
+          str: The NULL value in case of error, or a string containing the JSON file. This string must be freed by OrthancPluginFreeString().
+        """
+        ...
+    # This function returns a pointer to a newly created string containing a JSON file
+    def GetInstanceSimplifiedJson(self) -> str:
+        """
+        This function returns a pointer to a newly created string containing a JSON file. This JSON file encodes the tag hierarchy of the given DICOM instance. In contrast with ::OrthancPluginGetInstanceJson(), the returned JSON file is in its simplified version.
+
+        Returns:
+          str: The NULL value in case of error, or a string containing the JSON file. This string must be freed by OrthancPluginFreeString().
+        """
+        ...
+    # This function checks whether the DICOM instance of interest is associated with some metadata
+    def HasInstanceMetadata(self, metadata: str) -> int:
+        """
+        This function checks whether the DICOM instance of interest is associated with some metadata. As of Orthanc 0.8.1, in the callbacks registered by ::OrthancPluginRegisterOnStoredInstanceCallback(), the only possibly available metadata are "ReceptionDate", "RemoteAET" and "IndexInSeries".
+
+        Args:
+          metadata (str): The metadata of interest.
+
+        Returns:
+          int: 1 if the metadata is present, 0 if it is absent, -1 in case of error.
+        """
+        ...
+    # This functions returns the value of some metadata that is associated with the DICOM instance of interest
+    def GetInstanceMetadata(self, metadata: str) -> str:
+        """
+        This functions returns the value of some metadata that is associated with the DICOM instance of interest. Before calling this function, the existence of the metadata must have been checked with ::OrthancPluginHasInstanceMetadata().
+
+        Args:
+          metadata (str): The metadata of interest.
+
+        Returns:
+          str: The metadata value if success, NULL if error. Please note that the returned string belongs to the instance object and must NOT be deallocated. Please make a copy of the string if you wish to access it later.
+        """
+        ...
+    # This function returns the origin of a DICOM instance that has been received by Orthanc
+    def GetInstanceOrigin(self) -> InstanceOrigin:
+        """
+        This function returns the origin of a DICOM instance that has been received by Orthanc.
+
+        Returns:
+          InstanceOrigin: The origin of the instance.
+        """
+        ...
+    # This function returns a pointer to a newly created string that contains the transfer syntax UID of the DICOM instance
+    def GetInstanceTransferSyntaxUid(self) -> str:
+        """
+        This function returns a pointer to a newly created string that contains the transfer syntax UID of the DICOM instance. The empty string might be returned if this information is unknown.
+
+        Returns:
+          str: The NULL value in case of error, or a string containing the transfer syntax UID. This string must be freed by OrthancPluginFreeString().
+        """
+        ...
+    # This function returns a Boolean value indicating whether the DICOM instance contains the pixel data (7FE0,0010) tag
+    def HasInstancePixelData(self) -> int:
+        """
+        This function returns a Boolean value indicating whether the DICOM instance contains the pixel data (7FE0,0010) tag.
+
+        Returns:
+          int: "1" if the DICOM instance contains pixel data, or "0" if the tag is missing, or "-1" in the case of an error.
+        """
+        ...
+    # This function returns the number of frames that are part of a DICOM image managed by the Orthanc core
+    def GetInstanceFramesCount(self) -> int:
+        """
+        This function returns the number of frames that are part of a DICOM image managed by the Orthanc core.
+
+        Returns:
+          int: The number of frames (will be zero in the case of an error).
+        """
+        ...
+    # This function returns a memory buffer containing the raw content of a frame in a DICOM instance that is managed by the Orthanc core
+    def GetInstanceRawFrame(self, frame_index: int) -> bytes:
+        """
+        This function returns a memory buffer containing the raw content of a frame in a DICOM instance that is managed by the Orthanc core. This is notably useful for compressed transfer syntaxes, as it gives access to the embedded files (such as JPEG, JPEG-LS or JPEG2k). The Orthanc core transparently reassembles the fragments to extract the raw frame.
+
+        Args:
+          frame_index (int): The index of the frame of interest.
+
+        Returns:
+          bytes: 0 if success, or the error code if failure.
+        """
+        ...
+    # This function decodes one frame of a DICOM image that is managed by the Orthanc core
+    def GetInstanceDecodedFrame(self, frame_index: int) -> Image:
+        """
+        This function decodes one frame of a DICOM image that is managed by the Orthanc core.
+
+        Args:
+          frame_index (int): The index of the frame of interest.
+
+        Returns:
+          Image: The uncompressed image. It must be freed with OrthancPluginFreeImage().
+        """
+        ...
+    # This function returns a memory buffer containing the serialization of a DICOM instance that is managed by the Orthanc core
+    def SerializeDicomInstance(self) -> bytes:
+        """
+        This function returns a memory buffer containing the serialization of a DICOM instance that is managed by the Orthanc core.
+
+        Returns:
+          bytes: 0 if success, or the error code if failure.
+        """
+        ...
+    # This function takes as DICOM instance managed by the Orthanc core, and outputs a JSON string representing the tags of this DICOM file
+    def GetInstanceAdvancedJson(self, format: DicomToJsonFormat, flags: DicomToJsonFlags, max_string_length: int) -> str:
+        """
+        This function takes as DICOM instance managed by the Orthanc core, and outputs a JSON string representing the tags of this DICOM file.
+
+        Args:
+          format (DicomToJsonFormat): The output format.
+          flags (DicomToJsonFlags): Flags governing the output.
+          max_string_length (int): The maximum length of a field. Too long fields will be output as "null". The 0 value means no maximum length.
+
+        Returns:
+          str: The NULL value if the case of an error, or the JSON string. This string must be freed by OrthancPluginFreeString().
+        """
+        ...
+
+    # Get the content of the DICOM instance
+    def GetInstanceData(self) -> bytes:
+        """
+        Get the content of the DICOM instance.
+
+        Returns:
+          bytes: The DICOM data.
+        """
+        ...
+class DicomWebNode:
+    """
+    Node visited by DICOMweb conversion
+    """
+    ...
+
+
+class FindAnswers:
+    """
+    Answers to a DICOM C-FIND query
+    """
+    ...
+
+    # This function adds one answer (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request that is not related to modality worklists
+    def FindAddAnswer(self, dicom: bytes) -> None:
+        """
+        This function adds one answer (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request that is not related to modality worklists.
+
+        Args:
+          dicom (bytes): The answer to be added, encoded as a DICOM file.
+        """
+        ...
+    # This function marks as incomplete the set of answers corresponding to some C-Find SCP request that is not related to modality worklists
+    def FindMarkIncomplete(self) -> None:
+        """
+        This function marks as incomplete the set of answers corresponding to some C-Find SCP request that is not related to modality worklists. This must be used if canceling the handling of a request when too many answers are to be returned.
+        """
+        ...
+
+class FindMatcher:
+    """
+    Matcher for DICOM C-FIND query
+    """
+    ...
+
+    # This function checks whether one DICOM instance matches C-Find matcher that was previously allocated using OrthancPluginCreateFindMatcher()
+    def FindMatcherIsMatch(self, dicom: bytes) -> int:
+        """
+        This function checks whether one DICOM instance matches C-Find matcher that was previously allocated using OrthancPluginCreateFindMatcher().
+
+        Args:
+          dicom (bytes): The DICOM instance to be matched.
+
+        Returns:
+          int: 1 if the DICOM instance matches the query, 0 otherwise.
+        """
+        ...
+
+class FindQuery:
+    """
+    DICOM C-FIND query
+    """
+    ...
+
+    # This function returns the number of tags that are contained in the given C-Find query
+    def GetFindQuerySize(self) -> int:
+        """
+        This function returns the number of tags that are contained in the given C-Find query.
+
+        Returns:
+          int: The number of tags.
+        """
+        ...
+    # This function returns the symbolic name of one DICOM tag in the given C-Find query
+    def GetFindQueryTagName(self, index: int) -> str:
+        """
+        This function returns the symbolic name of one DICOM tag in the given C-Find query.
+
+        Args:
+          index (int): The index of the tag of interest.
+
+        Returns:
+          str: 0 if success, other value if error.
+        """
+        ...
+    # This function returns the value associated with one tag in the given C-Find query
+    def GetFindQueryValue(self, index: int) -> str:
+        """
+        This function returns the value associated with one tag in the given C-Find query.
+
+        Args:
+          index (int): The index of the tag of interest.
+
+        Returns:
+          str: 0 if success, other value if error.
+        """
+        ...
+
+    # This function returns the element of one DICOM tag in the given C-Find query
+    def GetFindQueryTagElement(self, index: int) -> int:
+        """
+        This function returns the element of one DICOM tag in the given C-Find query.
+
+        Args:
+          index (int): The index of the tag of interest.
+
+        Returns:
+          int: The value of the element.
+        """
+        ...
+    # This function returns the group of one DICOM tag in the given C-Find query
+    def GetFindQueryTagGroup(self, index: int) -> int:
+        """
+        This function returns the group of one DICOM tag in the given C-Find query.
+
+        Args:
+          index (int): The index of the tag of interest.
+
+        Returns:
+          int: The value of the group.
+        """
+        ...
+class Image:
+    """
+    2D image managed by the Orthanc core
+    """
+    ...
+
+    # This function returns the type of memory layout for the pixels of the given image
+    def GetImagePixelFormat(self) -> PixelFormat:
+        """
+        This function returns the type of memory layout for the pixels of the given image.
+
+        Returns:
+          PixelFormat: The pixel format.
+        """
+        ...
+    # This function returns the width of the given image
+    def GetImageWidth(self) -> int:
+        """
+        This function returns the width of the given image.
+
+        Returns:
+          int: The width.
+        """
+        ...
+    # This function returns the height of the given image
+    def GetImageHeight(self) -> int:
+        """
+        This function returns the height of the given image.
+
+        Returns:
+          int: The height.
+        """
+        ...
+    # This function returns the pitch of the given image
+    def GetImagePitch(self) -> int:
+        """
+        This function returns the pitch of the given image. The pitch is defined as the number of bytes between 2 successive lines of the image in the memory buffer.
+
+        Returns:
+          int: The pitch.
+        """
+        ...
+    # This function creates a new image, changing the memory layout of the pixels
+    def ConvertPixelFormat(self, target_format: PixelFormat) -> Image:
+        """
+        This function creates a new image, changing the memory layout of the pixels.
+
+        Args:
+          target_format (PixelFormat): The target pixel format.
+
+        Returns:
+          Image: The resulting image. It must be freed with OrthancPluginFreeImage().
+        """
+        ...
+    # This function draws some text on some image
+    def DrawText(self, font_index: int, utf8_text: str, x: int, y: int, r: int, g: int, b: int) -> None:
+        """
+        This function draws some text on some image.
+
+        Args:
+          font_index (int): The index of the font. This value must be less than OrthancPluginGetFontsCount().
+          utf8_text (str): The text to be drawn, encoded as an UTF-8 zero-terminated string.
+          x (int): The X position of the text over the image.
+          y (int): The Y position of the text over the image.
+          r (int): The value of the red color channel of the text.
+          g (int): The value of the green color channel of the text.
+          b (int): The value of the blue color channel of the text.
+        """
+        ...
+
+    # This function returns a pointer to the memory buffer that contains the pixels of the image
+    def GetImageBuffer(self) -> bytes:
+        """
+        This function returns a pointer to the memory buffer that contains the pixels of the image.
+
+        Returns:
+          bytes: The pixel data.
+        """
+        ...
+class Job:
+    """
+    Orthanc job
+    """
+    ...
+
+    # This function adds the given job to the pending jobs of Orthanc
+    def SubmitJob(self, priority: int) -> str:
+        """
+        This function adds the given job to the pending jobs of Orthanc. Orthanc will take take of freeing it by invoking the finalization callback provided to OrthancPluginCreateJob().
+
+        Args:
+          priority (int): The priority of the job.
+
+        Returns:
+          str: ID of the newly-submitted job. This string must be freed by OrthancPluginFreeString().
+        """
+        ...
+
+class Peers:
+    """
+    Orthanc peer
+    """
+    ...
+
+    # This function returns the number of Orthanc peers
+    def GetPeersCount(self) -> int:
+        """
+        This function returns the number of Orthanc peers.
+        This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function.
+
+        Returns:
+          int: The number of peers.
+        """
+        ...
+    # This function returns the symbolic name of the Orthanc peer, which corresponds to the key of the "OrthancPeers" configuration option of Orthanc
+    def GetPeerName(self, peer_index: int) -> str:
+        """
+        This function returns the symbolic name of the Orthanc peer, which corresponds to the key of the "OrthancPeers" configuration option of Orthanc.
+        This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function.
+
+        Args:
+          peer_index (int): The index of the peer of interest. This value must be lower than OrthancPluginGetPeersCount().
+
+        Returns:
+          str: The symbolic name, or NULL in the case of an error.
+        """
+        ...
+    # This function returns the base URL to the REST API of some Orthanc peer
+    def GetPeerUrl(self, peer_index: int) -> str:
+        """
+        This function returns the base URL to the REST API of some Orthanc peer.
+        This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function.
+
+        Args:
+          peer_index (int): The index of the peer of interest. This value must be lower than OrthancPluginGetPeersCount().
+
+        Returns:
+          str: The URL, or NULL in the case of an error.
+        """
+        ...
+    # This function returns some user-defined property of some Orthanc peer
+    def GetPeerUserProperty(self, peer_index: int, user_property: str) -> str:
+        """
+        This function returns some user-defined property of some Orthanc peer. An user-defined property is a property that is associated with the peer in the Orthanc configuration file, but that is not recognized by the Orthanc core.
+        This function is thread-safe: Several threads sharing the same OrthancPluginPeers object can simultaneously call this function.
+
+        Args:
+          peer_index (int): The index of the peer of interest. This value must be lower than OrthancPluginGetPeersCount().
+          user_property (str): The user property of interest.
+
+        Returns:
+          str: The value of the user property, or NULL if it is not defined.
+        """
+        ...
+
+class RestOutput:
+    """
+    Output for a call to the REST API of Orthanc
+    """
+    ...
+
+    # This function answers to a REST request with the content of a memory buffer
+    def AnswerBuffer(self, answer: bytes, mime_type: str) -> None:
+        """
+        This function answers to a REST request with the content of a memory buffer.
+
+        Args:
+          answer (bytes): Pointer to the memory buffer containing the answer.
+          mime_type (str): The MIME type of the answer.
+        """
+        ...
+    # This function answers to a REST request with a PNG image
+    def CompressAndAnswerPngImage(self, format: PixelFormat, width: int, height: int, pitch: int, buffer: bytes) -> None:
+        """
+        This function answers to a REST request with a PNG image. The parameters of this function describe a memory buffer that contains an uncompressed image. The image will be automatically compressed as a PNG image by the core system of Orthanc.
+
+        Args:
+          format (PixelFormat): The memory layout of the uncompressed image.
+          width (int): The width of the image.
+          height (int): The height of the image.
+          pitch (int): The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).
+          buffer (bytes): The memory buffer containing the uncompressed image.
+        """
+        ...
+    # This function answers to a REST request by redirecting the user to another URI using HTTP status 301
+    def Redirect(self, redirection: str) -> None:
+        """
+        This function answers to a REST request by redirecting the user to another URI using HTTP status 301.
+
+        Args:
+          redirection (str): Where to redirect.
+        """
+        ...
+    # This function answers to a REST request by sending a HTTP status code (such as "400 - Bad Request")
+    def SendHttpStatusCode(self, status: int) -> None:
+        """
+        This function answers to a REST request by sending a HTTP status code (such as "400 - Bad Request"). Note that: - Successful requests (status 200) must use ::OrthancPluginAnswerBuffer(). - Redirections (status 301) must use ::OrthancPluginRedirect(). - Unauthorized access (status 401) must use ::OrthancPluginSendUnauthorized(). - Methods not allowed (status 405) must use ::OrthancPluginSendMethodNotAllowed().
+
+        Args:
+          status (int): The HTTP status code to be sent.
+        """
+        ...
+    # This function answers to a REST request by signaling that it is not authorized
+    def SendUnauthorized(self, realm: str) -> None:
+        """
+        This function answers to a REST request by signaling that it is not authorized.
+
+        Args:
+          realm (str): The realm for the authorization process.
+        """
+        ...
+    # This function answers to a REST request by signaling that the queried URI does not support this method
+    def SendMethodNotAllowed(self, allowed_methods: str) -> None:
+        """
+        This function answers to a REST request by signaling that the queried URI does not support this method.
+
+        Args:
+          allowed_methods (str): The allowed methods for this URI (e.g. "GET,POST" after a PUT or a POST request).
+        """
+        ...
+    # This function sets a cookie in the HTTP client
+    def SetCookie(self, cookie: str, value: str) -> None:
+        """
+        This function sets a cookie in the HTTP client.
+
+        Args:
+          cookie (str): The cookie to be set.
+          value (str): The value of the cookie.
+        """
+        ...
+    # This function sets a HTTP header in the HTTP answer
+    def SetHttpHeader(self, key: str, value: str) -> None:
+        """
+        This function sets a HTTP header in the HTTP answer.
+
+        Args:
+          key (str): The HTTP header to be set.
+          value (str): The value of the HTTP header.
+        """
+        ...
+    # Initiates a HTTP multipart answer, as the result of a REST request
+    def StartMultipartAnswer(self, sub_type: str, content_type: str) -> None:
+        """
+        Initiates a HTTP multipart answer, as the result of a REST request.
+
+        Args:
+          sub_type (str): The sub-type of the multipart answer ("mixed" or "related").
+          content_type (str): The MIME type of the items in the multipart answer.
+        """
+        ...
+    # This function sends an item as a part of some HTTP multipart answer that was initiated by OrthancPluginStartMultipartAnswer()
+    def SendMultipartItem(self, answer: bytes) -> None:
+        """
+        This function sends an item as a part of some HTTP multipart answer that was initiated by OrthancPluginStartMultipartAnswer().
+
+        Args:
+          answer (bytes): Pointer to the memory buffer containing the item.
+        """
+        ...
+    # This function answers to a HTTP request by sending a HTTP status code (such as "400 - Bad Request"), together with a body describing the error
+    def SendHttpStatus(self, status: int, body: bytes) -> None:
+        """
+        This function answers to a HTTP request by sending a HTTP status code (such as "400 - Bad Request"), together with a body describing the error. The body will only be returned if the configuration option "HttpDescribeErrors" of Orthanc is set to "true".
+        Note that: - Successful requests (status 200) must use ::OrthancPluginAnswerBuffer(). - Redirections (status 301) must use ::OrthancPluginRedirect(). - Unauthorized access (status 401) must use ::OrthancPluginSendUnauthorized(). - Methods not allowed (status 405) must use ::OrthancPluginSendMethodNotAllowed().
+
+        Args:
+          status (int): The HTTP status code to be sent.
+          body (bytes): The body of the answer.
+        """
+        ...
+    # This function answers to a REST request with a JPEG image
+    def CompressAndAnswerJpegImage(self, format: PixelFormat, width: int, height: int, pitch: int, buffer: bytes, quality: int) -> None:
+        """
+        This function answers to a REST request with a JPEG image. The parameters of this function describe a memory buffer that contains an uncompressed image. The image will be automatically compressed as a JPEG image by the core system of Orthanc.
+
+        Args:
+          format (PixelFormat): The memory layout of the uncompressed image.
+          width (int): The width of the image.
+          height (int): The height of the image.
+          pitch (int): The pitch of the image (i.e. the number of bytes between 2 successive lines of the image in the memory buffer).
+          buffer (bytes): The memory buffer containing the uncompressed image.
+          quality (int): The quality of the JPEG encoding, between 1 (worst quality, best compression) and 100 (best quality, worst compression).
+        """
+        ...
+    # This function sets the detailed description associated with an HTTP error
+    def SetHttpErrorDetails(self, details: str, log: int) -> None:
+        """
+        This function sets the detailed description associated with an HTTP error. This description will be displayed in the "Details" field of the JSON body of the HTTP answer. It is only taken into consideration if the REST callback returns an error code that is different from "OrthancPluginErrorCode_Success", and if the "HttpDescribeErrors" configuration option of Orthanc is set to "true".
+
+        Args:
+          details (str): The details of the error message.
+          log (int): Whether to also write the detailed error to the Orthanc logs.
+        """
+        ...
+
+class ServerChunkedRequestReader:
+    """
+    Read for a chunked HTTP request
+    """
+    ...
+
+
+class StorageArea:
+    """
+    Storage area plugin
+    """
+    ...
+
+    # This function creates a new file inside the storage area that is currently used by Orthanc
+    def StorageAreaCreate(self, uuid: str, content: bytes, size: int, type: ContentType) -> None:
+        """
+        This function creates a new file inside the storage area that is currently used by Orthanc.
+
+        Args:
+          uuid (str): The identifier of the file to be created.
+          content (bytes): The content to store in the newly created file.
+          size (int): The size of the content.
+          type (ContentType): The type of the file content.
+        """
+        ...
+    # This function reads the content of a given file from the storage area that is currently used by Orthanc
+    def StorageAreaRead(self, uuid: str, type: ContentType) -> bytes:
+        """
+        This function reads the content of a given file from the storage area that is currently used by Orthanc.
+
+        Args:
+          uuid (str): The identifier of the file to be read.
+          type (ContentType): The type of the file content.
+
+        Returns:
+          bytes: 0 if success, other value if error.
+        """
+        ...
+    # This function removes a given file from the storage area that is currently used by Orthanc
+    def StorageAreaRemove(self, uuid: str, type: ContentType) -> None:
+        """
+        This function removes a given file from the storage area that is currently used by Orthanc.
+
+        Args:
+          uuid (str): The identifier of the file to be removed.
+          type (ContentType): The type of the file content.
+        """
+        ...
+    # This function requests the Orthanc core to reconstruct the main DICOM tags of all the resources of the given type
+    def ReconstructMainDicomTags(self, level: ResourceType) -> None:
+        """
+        This function requests the Orthanc core to reconstruct the main DICOM tags of all the resources of the given type. This function can only be used as a part of the upgrade of a custom database back-end. A database transaction will be automatically setup.
+
+        Args:
+          level (ResourceType): The type of the resources of interest.
+        """
+        ...
+
+class WorklistAnswers:
+    """
+    Answers to a DICOM C-FIND worklist query
+    """
+    ...
+
+    # This function adds one worklist (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request against modality worklists
+    def WorklistAddAnswer(self, query: WorklistQuery, dicom: bytes) -> None:
+        """
+        This function adds one worklist (encoded as a DICOM file) to the set of answers corresponding to some C-Find SCP request against modality worklists.
+
+        Args:
+          query (WorklistQuery): The worklist query, as received by the callback.
+          dicom (bytes): The worklist to answer, encoded as a DICOM file.
+        """
+        ...
+    # This function marks as incomplete the set of answers corresponding to some C-Find SCP request against modality worklists
+    def WorklistMarkIncomplete(self) -> None:
+        """
+        This function marks as incomplete the set of answers corresponding to some C-Find SCP request against modality worklists. This must be used if canceling the handling of a request when too many answers are to be returned.
+        """
+        ...
+
+class WorklistQuery:
+    """
+    DICOM C-FIND worklist query
+    """
+    ...
+
+    # This function checks whether one worklist (encoded as a DICOM file) matches the C-Find SCP query against modality worklists
+    def WorklistIsMatch(self, dicom: bytes) -> int:
+        """
+        This function checks whether one worklist (encoded as a DICOM file) matches the C-Find SCP query against modality worklists. This function must be called before adding the worklist as an answer through OrthancPluginWorklistAddAnswer().
+
+        Args:
+          dicom (bytes): The worklist to answer, encoded as a DICOM file.
+
+        Returns:
+          int: 1 if the worklist matches the query, 0 otherwise.
+        """
+        ...
+    # This function retrieves the DICOM file that underlies a C-Find SCP query against modality worklists
+    def WorklistGetDicomQuery(self) -> bytes:
+        """
+        This function retrieves the DICOM file that underlies a C-Find SCP query against modality worklists.
+
+        Returns:
+          bytes: 0 if success, other value if error.
+        """
+        ...
+
--- a/Sources/Autogenerated/sdk.cpp	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk.cpp	Tue Jul 02 19:06:54 2024 +0200
@@ -19,9 +19,13 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 #include "sdk.h"
 
 #include "../PythonLock.h"
+#include "../PythonThreadsAllower.h"
 
 #include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
 
--- a/Sources/Autogenerated/sdk.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 #pragma once
 
 #include "../PythonHeaderWrapper.h"
--- a/Sources/Autogenerated/sdk_GlobalFunctions.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_GlobalFunctions.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,15 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
+// Forward declaration of the custom global functions
+extern PyObject *RegisterOnChangeCallback(PyObject* module, PyObject *args);
+extern PyObject *RegisterRestCallback(PyObject* module, PyObject *args);
+// End of forward declarations
+
+
 static PyObject* sdk_OrthancPluginAutodetectMimeType(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginAutodetectMimeType()");
@@ -30,7 +39,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  const char* s = OrthancPluginAutodetectMimeType(OrthancPlugins::GetGlobalContext(), arg0);
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginAutodetectMimeType(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
   if (s == NULL)
   {
@@ -56,8 +70,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginBufferCompression(OrthancPlugins::GetGlobalContext(), *buffer, arg0.buf, arg0.len, static_cast<OrthancPluginCompressionType>(arg2), arg3);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginBufferCompression(OrthancPlugins::GetGlobalContext(), *buffer, arg0.buf, arg0.len, static_cast<OrthancPluginCompressionType>(arg2), arg3);
+  }
   PyBuffer_Release(&arg0);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -75,7 +94,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginCheckVersion()");
 
 
-  long value = OrthancPluginCheckVersion(OrthancPlugins::GetGlobalContext());
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginCheckVersion(OrthancPlugins::GetGlobalContext());
+  }
   
   return PyLong_FromLong(value);
 }
@@ -93,7 +117,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
-  long value = OrthancPluginCheckVersionAdvanced(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginCheckVersionAdvanced(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -114,8 +143,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (6 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginCompressJpegImage(OrthancPlugins::GetGlobalContext(), *buffer, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf, arg5);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginCompressJpegImage(OrthancPlugins::GetGlobalContext(), *buffer, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf, arg5);
+  }
   PyBuffer_Release(&arg4);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -143,8 +177,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (5 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginCompressPngImage(OrthancPlugins::GetGlobalContext(), *buffer, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginCompressPngImage(OrthancPlugins::GetGlobalContext(), *buffer, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf);
+  }
   PyBuffer_Release(&arg4);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -168,8 +207,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginComputeMd5(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginComputeMd5(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len));
+  }
   PyBuffer_Release(&arg0);
   if (s.GetContent() == NULL)
   {
@@ -193,8 +236,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginComputeSha1(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginComputeSha1(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len));
+  }
   PyBuffer_Release(&arg0);
   if (s.GetContent() == NULL)
   {
@@ -207,6 +254,83 @@
   }
 }
 
+static PyObject* sdk_OrthancPluginCreateDicom(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginCreateDicom()");
+
+  const char* arg0 = NULL;
+  PyObject* arg1 = NULL;
+  long int arg2 = 0;
+
+  if (!PyArg_ParseTuple(args, "sOl", &arg0, &arg1, &arg2))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
+    return NULL;
+  }
+
+  if (arg1 != Py_None && Py_TYPE(arg1) != GetOrthancPluginImageType())
+  {
+    PyErr_SetString(PyExc_TypeError, "Invalid orthanc.OrthancPluginImage object");
+    return NULL;
+  }
+
+  OrthancPlugins::MemoryBuffer buffer;
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginCreateDicom(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1 == Py_None ? NULL : reinterpret_cast<sdk_OrthancPluginImage_Object*>(arg1)->object_, static_cast<OrthancPluginCreateDicomFlags>(arg2));
+  }
+  
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;  
+  }
+}
+
+static PyObject* sdk_OrthancPluginCreateDicom2(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginCreateDicom2()");
+
+  const char* arg0 = NULL;
+  PyObject* arg1 = NULL;
+  long int arg2 = 0;
+  const char* arg3 = NULL;
+
+  if (!PyArg_ParseTuple(args, "sOls", &arg0, &arg1, &arg2, &arg3))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (4 arguments expected)");
+    return NULL;
+  }
+
+  if (arg1 != Py_None && Py_TYPE(arg1) != GetOrthancPluginImageType())
+  {
+    PyErr_SetString(PyExc_TypeError, "Invalid orthanc.OrthancPluginImage object");
+    return NULL;
+  }
+
+  OrthancPlugins::MemoryBuffer buffer;
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginCreateDicom2(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1 == Py_None ? NULL : reinterpret_cast<sdk_OrthancPluginImage_Object*>(arg1)->object_, static_cast<OrthancPluginCreateDicomFlags>(arg2), arg3);
+  }
+  
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;  
+  }
+}
+
 static PyObject* sdk_OrthancPluginCreateDicomInstance(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginCreateDicomInstance()");
@@ -218,8 +342,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginDicomInstance* obj = OrthancPluginCreateDicomInstance(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len);
+  OrthancPluginDicomInstance* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginCreateDicomInstance(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len);
+  }
   PyBuffer_Release(&arg0);
   if (obj == NULL)
   {
@@ -246,8 +375,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginFindMatcher* obj = OrthancPluginCreateFindMatcher(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len);
+  OrthancPluginFindMatcher* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginCreateFindMatcher(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len);
+  }
   PyBuffer_Release(&arg0);
   if (obj == NULL)
   {
@@ -276,8 +410,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginImage* obj = OrthancPluginCreateImage(OrthancPlugins::GetGlobalContext(), static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2);
+  OrthancPluginImage* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginCreateImage(OrthancPlugins::GetGlobalContext(), static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2);
+  }
   
   if (obj == NULL)
   {
@@ -305,8 +444,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginImage* obj = OrthancPluginDecodeDicomImage(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, arg2);
+  OrthancPluginImage* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginDecodeDicomImage(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, arg2);
+  }
   PyBuffer_Release(&arg0);
   if (obj == NULL)
   {
@@ -336,8 +480,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (4 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginDicomBufferToJson(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, static_cast<OrthancPluginDicomToJsonFormat>(arg2), static_cast<OrthancPluginDicomToJsonFlags>(arg3), arg4));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginDicomBufferToJson(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, static_cast<OrthancPluginDicomToJsonFormat>(arg2), static_cast<OrthancPluginDicomToJsonFlags>(arg3), arg4));
+  }
   PyBuffer_Release(&arg0);
   if (s.GetContent() == NULL)
   {
@@ -364,8 +512,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (4 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginDicomInstanceToJson(OrthancPlugins::GetGlobalContext(), arg0, static_cast<OrthancPluginDicomToJsonFormat>(arg1), static_cast<OrthancPluginDicomToJsonFlags>(arg2), arg3));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginDicomInstanceToJson(OrthancPlugins::GetGlobalContext(), arg0, static_cast<OrthancPluginDicomToJsonFormat>(arg1), static_cast<OrthancPluginDicomToJsonFlags>(arg2), arg3));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -389,7 +541,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginExtendOrthancExplorer(OrthancPlugins::GetGlobalContext(), arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginExtendOrthancExplorer(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -401,8 +557,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGenerateRestApiAuthorizationToken()");
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGenerateRestApiAuthorizationToken(OrthancPlugins::GetGlobalContext()));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGenerateRestApiAuthorizationToken(OrthancPlugins::GetGlobalContext()));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -420,8 +580,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGenerateUuid()");
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGenerateUuid(OrthancPlugins::GetGlobalContext()));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGenerateUuid(OrthancPlugins::GetGlobalContext()));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -445,8 +609,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetCommandLineArgument(OrthancPlugins::GetGlobalContext(), arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetCommandLineArgument(OrthancPlugins::GetGlobalContext(), arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -464,7 +632,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetCommandLineArgumentsCount()");
 
 
-  long value = OrthancPluginGetCommandLineArgumentsCount(OrthancPlugins::GetGlobalContext());
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetCommandLineArgumentsCount(OrthancPlugins::GetGlobalContext());
+  }
   
   return PyLong_FromLong(value);
 }
@@ -474,8 +647,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetConfiguration()");
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetConfiguration(OrthancPlugins::GetGlobalContext()));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetConfiguration(OrthancPlugins::GetGlobalContext()));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -493,8 +670,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetConfigurationPath()");
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetConfigurationPath(OrthancPlugins::GetGlobalContext()));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetConfigurationPath(OrthancPlugins::GetGlobalContext()));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -518,8 +699,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginGetDicomForInstance(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginGetDicomForInstance(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -543,7 +729,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  const char* s = OrthancPluginGetErrorDescription(OrthancPlugins::GetGlobalContext(), static_cast<OrthancPluginErrorCode>(arg0));
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginGetErrorDescription(OrthancPlugins::GetGlobalContext(), static_cast<OrthancPluginErrorCode>(arg0));
+  }
   
   if (s == NULL)
   {
@@ -561,7 +752,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetExpectedDatabaseVersion()");
 
 
-  long value = OrthancPluginGetExpectedDatabaseVersion(OrthancPlugins::GetGlobalContext());
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetExpectedDatabaseVersion(OrthancPlugins::GetGlobalContext());
+  }
   
   return PyLong_FromLong(value);
 }
@@ -577,7 +773,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  const char* s = OrthancPluginGetFontName(OrthancPlugins::GetGlobalContext(), arg0);
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginGetFontName(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
   if (s == NULL)
   {
@@ -601,7 +802,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  long value = OrthancPluginGetFontSize(OrthancPlugins::GetGlobalContext(), arg0);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetFontSize(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -611,7 +817,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetFontsCount()");
 
 
-  long value = OrthancPluginGetFontsCount(OrthancPlugins::GetGlobalContext());
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetFontsCount(OrthancPlugins::GetGlobalContext());
+  }
   
   return PyLong_FromLong(value);
 }
@@ -628,8 +839,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetGlobalProperty(OrthancPlugins::GetGlobalContext(), arg0, arg1));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetGlobalProperty(OrthancPlugins::GetGlobalContext(), arg0, arg1));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -647,8 +862,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetOrthancDirectory()");
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetOrthancDirectory(OrthancPlugins::GetGlobalContext()));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetOrthancDirectory(OrthancPlugins::GetGlobalContext()));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -666,8 +885,12 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetOrthancPath()");
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetOrthancPath(OrthancPlugins::GetGlobalContext()));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetOrthancPath(OrthancPlugins::GetGlobalContext()));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -685,8 +908,13 @@
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetPeers()");
 
 
+
   // This is the case of a constructor
-  OrthancPluginPeers* obj = OrthancPluginGetPeers(OrthancPlugins::GetGlobalContext());
+  OrthancPluginPeers* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginGetPeers(OrthancPlugins::GetGlobalContext());
+  }
   
   if (obj == NULL)
   {
@@ -715,8 +943,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetTagName(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetTagName(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -742,7 +974,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginHttpDelete(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginHttpDelete(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -770,8 +1007,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginHttpGet(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1, arg2);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginHttpGet(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1, arg2);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -798,8 +1040,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (4 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginHttpPost(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len, arg3, arg4);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginHttpPost(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len, arg3, arg4);
+  }
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -826,8 +1073,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (4 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginHttpPut(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len, arg3, arg4);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginHttpPut(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len, arg3, arg4);
+  }
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -851,7 +1103,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginLogError(OrthancPlugins::GetGlobalContext(), arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginLogError(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -869,7 +1125,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginLogInfo(OrthancPlugins::GetGlobalContext(), arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginLogInfo(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -887,7 +1147,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginLogWarning(OrthancPlugins::GetGlobalContext(), arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginLogWarning(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -905,8 +1169,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginLookupInstance(OrthancPlugins::GetGlobalContext(), arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginLookupInstance(OrthancPlugins::GetGlobalContext(), arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -930,8 +1198,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginLookupPatient(OrthancPlugins::GetGlobalContext(), arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginLookupPatient(OrthancPlugins::GetGlobalContext(), arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -955,8 +1227,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginLookupSeries(OrthancPlugins::GetGlobalContext(), arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginLookupSeries(OrthancPlugins::GetGlobalContext(), arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -980,8 +1256,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginLookupStudy(OrthancPlugins::GetGlobalContext(), arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginLookupStudy(OrthancPlugins::GetGlobalContext(), arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -1005,8 +1285,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginLookupStudyWithAccessionNumber(OrthancPlugins::GetGlobalContext(), arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginLookupStudyWithAccessionNumber(OrthancPlugins::GetGlobalContext(), arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -1030,8 +1314,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginReadFile(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginReadFile(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -1060,7 +1349,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (6 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginRegisterDictionaryTag(OrthancPlugins::GetGlobalContext(), arg0, arg1, static_cast<OrthancPluginValueRepresentation>(arg2), arg3, arg4, arg5);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRegisterDictionaryTag(OrthancPlugins::GetGlobalContext(), arg0, arg1, static_cast<OrthancPluginValueRepresentation>(arg2), arg3, arg4, arg5);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -1088,7 +1382,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginRegisterErrorCode(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRegisterErrorCode(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -1120,7 +1419,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (7 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginRegisterPrivateDictionaryTag(OrthancPlugins::GetGlobalContext(), arg0, arg1, static_cast<OrthancPluginValueRepresentation>(arg2), arg3, arg4, arg5, arg6);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRegisterPrivateDictionaryTag(OrthancPlugins::GetGlobalContext(), arg0, arg1, static_cast<OrthancPluginValueRepresentation>(arg2), arg3, arg4, arg5, arg6);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -1146,7 +1450,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginRestApiDelete(OrthancPlugins::GetGlobalContext(), arg0);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiDelete(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -1172,7 +1481,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginRestApiDeleteAfterPlugins(OrthancPlugins::GetGlobalContext(), arg0);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiDeleteAfterPlugins(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -1198,8 +1512,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginRestApiGet(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiGet(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -1223,8 +1542,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginRestApiGetAfterPlugins(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiGetAfterPlugins(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -1249,8 +1573,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginRestApiPost(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiPost(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  }
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -1275,8 +1604,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginRestApiPostAfterPlugins(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiPostAfterPlugins(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  }
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -1301,8 +1635,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginRestApiPut(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiPut(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  }
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -1327,8 +1666,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginRestApiPutAfterPlugins(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginRestApiPutAfterPlugins(OrthancPlugins::GetGlobalContext(), *buffer, arg0, arg1.buf, arg1.len);
+  }
   PyBuffer_Release(&arg1);
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -1352,7 +1696,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginSetDescription(OrthancPlugins::GetGlobalContext(), arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSetDescription(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -1371,7 +1719,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginSetGlobalProperty(OrthancPlugins::GetGlobalContext(), arg0, arg1);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginSetGlobalProperty(OrthancPlugins::GetGlobalContext(), arg0, arg1);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -1399,7 +1752,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
-  OrthancPluginSetMetricsValue(OrthancPlugins::GetGlobalContext(), arg0, arg1, static_cast<OrthancPluginMetricsType>(arg2));
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSetMetricsValue(OrthancPlugins::GetGlobalContext(), arg0, arg1, static_cast<OrthancPluginMetricsType>(arg2));
+  }
   
 
   Py_INCREF(Py_None);
@@ -1417,7 +1774,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginSetRootUri(OrthancPlugins::GetGlobalContext(), arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSetRootUri(OrthancPlugins::GetGlobalContext(), arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -1436,8 +1797,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginDicomInstance* obj = OrthancPluginTranscodeDicomInstance(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, arg2);
+  OrthancPluginDicomInstance* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginTranscodeDicomInstance(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, arg2);
+  }
   PyBuffer_Release(&arg0);
   if (obj == NULL)
   {
@@ -1465,8 +1831,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginImage* obj = OrthancPluginUncompressImage(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, static_cast<OrthancPluginImageFormat>(arg2));
+  OrthancPluginImage* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginUncompressImage(OrthancPlugins::GetGlobalContext(), arg0.buf, arg0.len, static_cast<OrthancPluginImageFormat>(arg2));
+  }
   PyBuffer_Release(&arg0);
   if (obj == NULL)
   {
@@ -1494,7 +1865,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginWriteFile(OrthancPlugins::GetGlobalContext(), arg0, arg1.buf, arg1.len);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginWriteFile(OrthancPlugins::GetGlobalContext(), arg0, arg1.buf, arg1.len);
+  }
   PyBuffer_Release(&arg1);
 
   if (code == OrthancPluginErrorCode_Success)
@@ -1528,6 +1904,10 @@
     "Generated from C function OrthancPluginComputeMd5()" },
   { "ComputeSha1", sdk_OrthancPluginComputeSha1, METH_VARARGS,
     "Generated from C function OrthancPluginComputeSha1()" },
+  { "CreateDicom", sdk_OrthancPluginCreateDicom, METH_VARARGS,
+    "Generated from C function OrthancPluginCreateDicom()" },
+  { "CreateDicom2", sdk_OrthancPluginCreateDicom2, METH_VARARGS,
+    "Generated from C function OrthancPluginCreateDicom2()" },
   { "CreateDicomInstance", sdk_OrthancPluginCreateDicomInstance, METH_VARARGS,
     "Generated from C function OrthancPluginCreateDicomInstance()" },
   { "CreateFindMatcher", sdk_OrthancPluginCreateFindMatcher, METH_VARARGS,
@@ -1638,6 +2018,10 @@
     "Generated from C function OrthancPluginUncompressImage()" },
   { "WriteFile", sdk_OrthancPluginWriteFile, METH_VARARGS,
     "Generated from C function OrthancPluginWriteFile()" },
+  { "RegisterOnChangeCallback", RegisterOnChangeCallback, METH_VARARGS,
+    "Implemented in C++ function RegisterOnChangeCallback()" },
+  { "RegisterRestCallback", RegisterRestCallback, METH_VARARGS,
+    "Implemented in C++ function RegisterRestCallback()" },
   { NULL, NULL }
 };
 
--- a/Sources/Autogenerated/sdk_OrthancPluginChangeType.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginChangeType.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginConstraintType.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginConstraintType.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginContentType.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginContentType.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginCreateDicomFlags.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginCreateDicomFlags.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomInstance.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomInstance.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginDicomInstance_OrthancPluginGetInstanceRemoteAet(
   sdk_OrthancPluginDicomInstance_Object* self, PyObject *args);
@@ -52,8 +55,7 @@
 
 
 // Forward declaration of the custom methods
-extern PyObject *GetInstanceData(
-  sdk_OrthancPluginDicomInstance_Object* self, PyObject *args);
+extern PyObject *GetInstanceData(sdk_OrthancPluginDicomInstance_Object* self, PyObject *args);
 // End of forward declarations
 
 
@@ -102,7 +104,7 @@
     "Generated from C function OrthancPluginGetInstanceAdvancedJson()" },
   { "GetInstanceData",
     (PyCFunction) GetInstanceData, METH_VARARGS,
-    "Generated from C function OrthancPluginGetInstanceData()" },
+    "Implemented in C++ function GetInstanceData()" },
   { NULL }  /* Sentinel */
 };
 
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomInstance.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomInstance.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginDicomInstance_OrthancPluginGetInstanceRemoteAet(
   sdk_OrthancPluginDicomInstance_Object* self, PyObject *args)
@@ -11,7 +35,12 @@
   }
 
 
-  const char* s = OrthancPluginGetInstanceRemoteAet(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginGetInstanceRemoteAet(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   if (s == NULL)
   {
@@ -36,7 +65,12 @@
   }
 
 
-  long value = OrthancPluginGetInstanceSize(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetInstanceSize(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -53,8 +87,12 @@
   }
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetInstanceJson(OrthancPlugins::GetGlobalContext(), self->object_));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetInstanceJson(OrthancPlugins::GetGlobalContext(), self->object_));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -79,8 +117,12 @@
   }
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetInstanceSimplifiedJson(OrthancPlugins::GetGlobalContext(), self->object_));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetInstanceSimplifiedJson(OrthancPlugins::GetGlobalContext(), self->object_));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -111,7 +153,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  long value = OrthancPluginHasInstanceMetadata(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginHasInstanceMetadata(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -134,7 +181,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  const char* s = OrthancPluginGetInstanceMetadata(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginGetInstanceMetadata(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
   if (s == NULL)
   {
@@ -159,7 +211,12 @@
   }
 
 
-  OrthancPluginInstanceOrigin value = OrthancPluginGetInstanceOrigin(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  OrthancPluginInstanceOrigin value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetInstanceOrigin(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -176,8 +233,12 @@
   }
 
 
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetInstanceTransferSyntaxUid(OrthancPlugins::GetGlobalContext(), self->object_));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetInstanceTransferSyntaxUid(OrthancPlugins::GetGlobalContext(), self->object_));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -202,7 +263,12 @@
   }
 
 
-  long value = OrthancPluginHasInstancePixelData(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginHasInstancePixelData(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -219,7 +285,12 @@
   }
 
 
-  long value = OrthancPluginGetInstanceFramesCount(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetInstanceFramesCount(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -242,8 +313,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginGetInstanceRawFrame(OrthancPlugins::GetGlobalContext(), *buffer, self->object_, arg0);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginGetInstanceRawFrame(OrthancPlugins::GetGlobalContext(), *buffer, self->object_, arg0);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -274,8 +350,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginImage* obj = OrthancPluginGetInstanceDecodedFrame(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  OrthancPluginImage* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginGetInstanceDecodedFrame(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
   if (obj == NULL)
   {
@@ -303,8 +384,13 @@
   }
 
 
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginSerializeDicomInstance(OrthancPlugins::GetGlobalContext(), *buffer, self->object_);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginSerializeDicomInstance(OrthancPlugins::GetGlobalContext(), *buffer, self->object_);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -337,8 +423,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetInstanceAdvancedJson(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginDicomToJsonFormat>(arg0), static_cast<OrthancPluginDicomToJsonFlags>(arg1), arg2));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetInstanceAdvancedJson(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginDicomToJsonFormat>(arg0), static_cast<OrthancPluginDicomToJsonFlags>(arg1), arg2));
+  }
   
   if (s.GetContent() == NULL)
   {
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomToJsonFlags.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomToJsonFlags.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomToJsonFormat.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomToJsonFormat.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomWebBinaryMode.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomWebBinaryMode.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomWebNode.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomWebNode.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 // End of forward declarations
 
--- a/Sources/Autogenerated/sdk_OrthancPluginDicomWebNode.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginDicomWebNode.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,1 +1,25 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
--- a/Sources/Autogenerated/sdk_OrthancPluginErrorCode.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginErrorCode.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginFindAnswers.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginFindAnswers.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginFindAnswers_OrthancPluginFindAddAnswer(
   sdk_OrthancPluginFindAnswers_Object* self, PyObject *args);
--- a/Sources/Autogenerated/sdk_OrthancPluginFindAnswers.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginFindAnswers.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginFindAnswers_OrthancPluginFindAddAnswer(
   sdk_OrthancPluginFindAnswers_Object* self, PyObject *args)
@@ -17,7 +41,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginFindAddAnswer(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginFindAddAnswer(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+  }
   PyBuffer_Release(&arg0);
 
   if (code == OrthancPluginErrorCode_Success)
@@ -44,7 +73,12 @@
   }
 
 
-  OrthancPluginErrorCode code = OrthancPluginFindMarkIncomplete(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginFindMarkIncomplete(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
--- a/Sources/Autogenerated/sdk_OrthancPluginFindMatcher.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginFindMatcher.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginFindMatcher_OrthancPluginFindMatcherIsMatch(
   sdk_OrthancPluginFindMatcher_Object* self, PyObject *args);
--- a/Sources/Autogenerated/sdk_OrthancPluginFindMatcher.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginFindMatcher.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginFindMatcher_OrthancPluginFindMatcherIsMatch(
   sdk_OrthancPluginFindMatcher_Object* self, PyObject *args)
@@ -17,7 +41,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  long value = OrthancPluginFindMatcherIsMatch(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginFindMatcherIsMatch(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+  }
   PyBuffer_Release(&arg0);
   return PyLong_FromLong(value);
 }
--- a/Sources/Autogenerated/sdk_OrthancPluginFindQuery.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginFindQuery.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginFindQuery_OrthancPluginGetFindQuerySize(
   sdk_OrthancPluginFindQuery_Object* self, PyObject *args);
@@ -30,10 +33,8 @@
 
 
 // Forward declaration of the custom methods
-extern PyObject *GetFindQueryTagGroup(
-  sdk_OrthancPluginFindQuery_Object* self, PyObject *args);
-extern PyObject *GetFindQueryTagElement(
-  sdk_OrthancPluginFindQuery_Object* self, PyObject *args);
+extern PyObject *GetFindQueryTagElement(sdk_OrthancPluginFindQuery_Object* self, PyObject *args);
+extern PyObject *GetFindQueryTagGroup(sdk_OrthancPluginFindQuery_Object* self, PyObject *args);
 // End of forward declarations
 
 
@@ -47,12 +48,12 @@
   { "GetFindQueryValue",
     (PyCFunction) sdk_OrthancPluginFindQuery_OrthancPluginGetFindQueryValue, METH_VARARGS,
     "Generated from C function OrthancPluginGetFindQueryValue()" },
+  { "GetFindQueryTagElement",
+    (PyCFunction) GetFindQueryTagElement, METH_VARARGS,
+    "Implemented in C++ function GetFindQueryTagElement()" },
   { "GetFindQueryTagGroup",
     (PyCFunction) GetFindQueryTagGroup, METH_VARARGS,
-    "Generated from C function OrthancPluginGetFindQueryTag()" },
-  { "GetFindQueryTagElement",
-    (PyCFunction) GetFindQueryTagElement, METH_VARARGS,
-    "Generated from C function OrthancPluginGetFindQueryTag()" },
+    "Implemented in C++ function GetFindQueryTagGroup()" },
   { NULL }  /* Sentinel */
 };
 
--- a/Sources/Autogenerated/sdk_OrthancPluginFindQuery.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginFindQuery.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginFindQuery_OrthancPluginGetFindQuerySize(
   sdk_OrthancPluginFindQuery_Object* self, PyObject *args)
@@ -11,7 +35,12 @@
   }
 
 
-  long value = OrthancPluginGetFindQuerySize(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetFindQuerySize(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -34,8 +63,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetFindQueryTagName(OrthancPlugins::GetGlobalContext(), self->object_, arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetFindQueryTagName(OrthancPlugins::GetGlobalContext(), self->object_, arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
@@ -66,8 +99,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginGetFindQueryValue(OrthancPlugins::GetGlobalContext(), self->object_, arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginGetFindQueryValue(OrthancPlugins::GetGlobalContext(), self->object_, arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
--- a/Sources/Autogenerated/sdk_OrthancPluginHttpMethod.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginHttpMethod.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginIdentifierConstraint.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginIdentifierConstraint.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginImage.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginImage.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginImage_OrthancPluginGetImagePixelFormat(
   sdk_OrthancPluginImage_Object* self, PyObject *args);
@@ -36,8 +39,7 @@
 
 
 // Forward declaration of the custom methods
-extern PyObject *GetImageBuffer(
-  sdk_OrthancPluginImage_Object* self, PyObject *args);
+extern PyObject *GetImageBuffer(sdk_OrthancPluginImage_Object* self, PyObject *args);
 // End of forward declarations
 
 
@@ -62,7 +64,7 @@
     "Generated from C function OrthancPluginDrawText()" },
   { "GetImageBuffer",
     (PyCFunction) GetImageBuffer, METH_VARARGS,
-    "Generated from C function OrthancPluginGetImageBuffer()" },
+    "Implemented in C++ function GetImageBuffer()" },
   { NULL }  /* Sentinel */
 };
 
--- a/Sources/Autogenerated/sdk_OrthancPluginImage.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginImage.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginImage_OrthancPluginGetImagePixelFormat(
   sdk_OrthancPluginImage_Object* self, PyObject *args)
@@ -11,7 +35,12 @@
   }
 
 
-  OrthancPluginPixelFormat value = OrthancPluginGetImagePixelFormat(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  OrthancPluginPixelFormat value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetImagePixelFormat(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -28,7 +57,12 @@
   }
 
 
-  long value = OrthancPluginGetImageWidth(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetImageWidth(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -45,7 +79,12 @@
   }
 
 
-  long value = OrthancPluginGetImageHeight(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetImageHeight(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -62,7 +101,12 @@
   }
 
 
-  long value = OrthancPluginGetImagePitch(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetImagePitch(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -85,8 +129,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   // This is the case of a constructor
-  OrthancPluginImage* obj = OrthancPluginConvertPixelFormat(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginPixelFormat>(arg0));
+  OrthancPluginImage* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginConvertPixelFormat(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginPixelFormat>(arg0));
+  }
   
   if (obj == NULL)
   {
@@ -126,7 +175,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (7 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginDrawText(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginDrawText(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
--- a/Sources/Autogenerated/sdk_OrthancPluginImageFormat.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginImageFormat.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginInstanceOrigin.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginInstanceOrigin.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginJob.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginJob.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginJob_OrthancPluginSubmitJob(
   sdk_OrthancPluginJob_Object* self, PyObject *args);
--- a/Sources/Autogenerated/sdk_OrthancPluginJob.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginJob.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginJob_OrthancPluginSubmitJob(
   sdk_OrthancPluginJob_Object* self, PyObject *args)
@@ -17,8 +41,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::OrthancString s;
-  s.Assign(OrthancPluginSubmitJob(OrthancPlugins::GetGlobalContext(), self->object_, arg0));
+  {
+    PythonThreadsAllower allower;
+    s.Assign(OrthancPluginSubmitJob(OrthancPlugins::GetGlobalContext(), self->object_, arg0));
+  }
   
   if (s.GetContent() == NULL)
   {
--- a/Sources/Autogenerated/sdk_OrthancPluginJobStepStatus.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginJobStepStatus.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginJobStopReason.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginJobStopReason.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginMetricsType.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginMetricsType.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginPeers.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginPeers.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginPeers_OrthancPluginGetPeersCount(
   sdk_OrthancPluginPeers_Object* self, PyObject *args);
--- a/Sources/Autogenerated/sdk_OrthancPluginPeers.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginPeers.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginPeers_OrthancPluginGetPeersCount(
   sdk_OrthancPluginPeers_Object* self, PyObject *args)
@@ -11,7 +35,12 @@
   }
 
 
-  long value = OrthancPluginGetPeersCount(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginGetPeersCount(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
   return PyLong_FromLong(value);
 }
@@ -34,7 +63,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  const char* s = OrthancPluginGetPeerName(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginGetPeerName(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
   if (s == NULL)
   {
@@ -65,7 +99,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  const char* s = OrthancPluginGetPeerUrl(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginGetPeerUrl(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
   if (s == NULL)
   {
@@ -97,7 +136,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  const char* s = OrthancPluginGetPeerUserProperty(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+
+  const char* s;
+  {
+    PythonThreadsAllower allower;
+    s = OrthancPluginGetPeerUserProperty(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+  }
   
   if (s == NULL)
   {
--- a/Sources/Autogenerated/sdk_OrthancPluginPixelFormat.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginPixelFormat.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginReceivedInstanceAction.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginReceivedInstanceAction.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginResourceType.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginResourceType.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginRestOutput.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginRestOutput.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginRestOutput_OrthancPluginAnswerBuffer(
   sdk_OrthancPluginRestOutput_Object* self, PyObject *args);
--- a/Sources/Autogenerated/sdk_OrthancPluginRestOutput.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginRestOutput.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginRestOutput_OrthancPluginAnswerBuffer(
   sdk_OrthancPluginRestOutput_Object* self, PyObject *args)
@@ -18,7 +42,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len, arg2);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len, arg2);
+  }
   PyBuffer_Release(&arg0);
 
   Py_INCREF(Py_None);
@@ -47,7 +75,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (5 arguments expected)");
     return NULL;
   }
-  OrthancPluginCompressAndAnswerPngImage(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginCompressAndAnswerPngImage(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf);
+  }
   PyBuffer_Release(&arg4);
 
   Py_INCREF(Py_None);
@@ -72,7 +104,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginRedirect(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginRedirect(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -97,7 +133,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -122,7 +162,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginSendUnauthorized(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSendUnauthorized(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -147,7 +191,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), self->object_, arg0);
+  }
   
 
   Py_INCREF(Py_None);
@@ -173,7 +221,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginSetCookie(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSetCookie(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+  }
   
 
   Py_INCREF(Py_None);
@@ -199,7 +251,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginSetHttpHeader(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSetHttpHeader(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+  }
   
 
   Py_INCREF(Py_None);
@@ -225,7 +281,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginStartMultipartAnswer(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginStartMultipartAnswer(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -258,7 +319,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginSendMultipartItem(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginSendMultipartItem(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+  }
   PyBuffer_Release(&arg0);
 
   if (code == OrthancPluginErrorCode_Success)
@@ -292,7 +358,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginSendHttpStatus(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1.buf, arg1.len);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSendHttpStatus(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1.buf, arg1.len);
+  }
   PyBuffer_Release(&arg1);
 
   Py_INCREF(Py_None);
@@ -322,7 +392,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (6 arguments expected)");
     return NULL;
   }
-  OrthancPluginCompressAndAnswerJpegImage(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf, arg5);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginCompressAndAnswerJpegImage(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginPixelFormat>(arg0), arg1, arg2, arg3, arg4.buf, arg5);
+  }
   PyBuffer_Release(&arg4);
 
   Py_INCREF(Py_None);
@@ -348,7 +422,11 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginSetHttpErrorDetails(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginSetHttpErrorDetails(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1);
+  }
   
 
   Py_INCREF(Py_None);
--- a/Sources/Autogenerated/sdk_OrthancPluginServerChunkedRequestReader.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginServerChunkedRequestReader.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 // End of forward declarations
 
--- a/Sources/Autogenerated/sdk_OrthancPluginServerChunkedRequestReader.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginServerChunkedRequestReader.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,1 +1,25 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
--- a/Sources/Autogenerated/sdk_OrthancPluginStorageArea.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginStorageArea.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginStorageArea_OrthancPluginStorageAreaCreate(
   sdk_OrthancPluginStorageArea_Object* self, PyObject *args);
--- a/Sources/Autogenerated/sdk_OrthancPluginStorageArea.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginStorageArea.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginStorageArea_OrthancPluginStorageAreaCreate(
   sdk_OrthancPluginStorageArea_Object* self, PyObject *args)
@@ -20,7 +44,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (4 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginStorageAreaCreate(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1.buf, arg2, static_cast<OrthancPluginContentType>(arg3));
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginStorageAreaCreate(OrthancPlugins::GetGlobalContext(), self->object_, arg0, arg1.buf, arg2, static_cast<OrthancPluginContentType>(arg3));
+  }
   PyBuffer_Release(&arg1);
 
   if (code == OrthancPluginErrorCode_Success)
@@ -54,8 +83,13 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginStorageAreaRead(OrthancPlugins::GetGlobalContext(), *buffer, self->object_, arg0, static_cast<OrthancPluginContentType>(arg1));
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginStorageAreaRead(OrthancPlugins::GetGlobalContext(), *buffer, self->object_, arg0, static_cast<OrthancPluginContentType>(arg1));
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
@@ -87,7 +121,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginStorageAreaRemove(OrthancPlugins::GetGlobalContext(), self->object_, arg0, static_cast<OrthancPluginContentType>(arg1));
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginStorageAreaRemove(OrthancPlugins::GetGlobalContext(), self->object_, arg0, static_cast<OrthancPluginContentType>(arg1));
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
@@ -120,7 +159,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  OrthancPluginErrorCode code = OrthancPluginReconstructMainDicomTags(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginResourceType>(arg0));
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginReconstructMainDicomTags(OrthancPlugins::GetGlobalContext(), self->object_, static_cast<OrthancPluginResourceType>(arg0));
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
--- a/Sources/Autogenerated/sdk_OrthancPluginStorageCommitmentFailureReason.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginStorageCommitmentFailureReason.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginValueRepresentation.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginValueRepresentation.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 typedef struct 
 {
   PyObject_HEAD
--- a/Sources/Autogenerated/sdk_OrthancPluginWorklistAnswers.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginWorklistAnswers.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,25 +19,28 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
+static PyObject *sdk_OrthancPluginWorklistAnswers_OrthancPluginWorklistAddAnswer(
+  sdk_OrthancPluginWorklistAnswers_Object* self, PyObject *args);
 static PyObject *sdk_OrthancPluginWorklistAnswers_OrthancPluginWorklistMarkIncomplete(
   sdk_OrthancPluginWorklistAnswers_Object* self, PyObject *args);
 // End of forward declarations
 
 
 // Forward declaration of the custom methods
-extern PyObject *WorklistAddAnswer(
-  sdk_OrthancPluginWorklistAnswers_Object* self, PyObject *args);
 // End of forward declarations
 
 
 static PyMethodDef sdk_OrthancPluginWorklistAnswers_Methods[] = {
+  { "WorklistAddAnswer",
+    (PyCFunction) sdk_OrthancPluginWorklistAnswers_OrthancPluginWorklistAddAnswer, METH_VARARGS,
+    "Generated from C function OrthancPluginWorklistAddAnswer()" },
   { "WorklistMarkIncomplete",
     (PyCFunction) sdk_OrthancPluginWorklistAnswers_OrthancPluginWorklistMarkIncomplete, METH_VARARGS,
     "Generated from C function OrthancPluginWorklistMarkIncomplete()" },
-  { "WorklistAddAnswer",
-    (PyCFunction) WorklistAddAnswer, METH_VARARGS,
-    "Generated from C function OrthancPluginWorklistAddAnswer()" },
   { NULL }  /* Sentinel */
 };
 
--- a/Sources/Autogenerated/sdk_OrthancPluginWorklistAnswers.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginWorklistAnswers.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,4 +1,73 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
+static PyObject *sdk_OrthancPluginWorklistAnswers_OrthancPluginWorklistAddAnswer(
+  sdk_OrthancPluginWorklistAnswers_Object* self, PyObject *args)
+{
+  PythonLock::LogCall("Calling method OrthancPluginWorklistAddAnswer() on object of class OrthancPluginWorklistAnswers");
+
+  if (self->object_ == NULL)
+  {
+    PyErr_SetString(PyExc_ValueError, "Invalid object");
+    return NULL;
+  }
+
+  PyObject* arg0 = NULL;
+  Py_buffer arg1;
+
+  if (!PyArg_ParseTuple(args, "Os*", &arg0, &arg1))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
+    return NULL;
+  }
+
+  if (arg0 != Py_None && Py_TYPE(arg0) != GetOrthancPluginWorklistQueryType())
+  {
+    PyErr_SetString(PyExc_TypeError, "Invalid orthanc.OrthancPluginWorklistQuery object");
+    return NULL;
+  }
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginWorklistAddAnswer(OrthancPlugins::GetGlobalContext(), self->object_, arg0 == Py_None ? NULL : reinterpret_cast<sdk_OrthancPluginWorklistQuery_Object*>(arg0)->object_, arg1.buf, arg1.len);
+  }
+  PyBuffer_Release(&arg1);
+
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;
+  }
+}
+
 static PyObject *sdk_OrthancPluginWorklistAnswers_OrthancPluginWorklistMarkIncomplete(
   sdk_OrthancPluginWorklistAnswers_Object* self, PyObject *args)
 {
@@ -11,7 +80,12 @@
   }
 
 
-  OrthancPluginErrorCode code = OrthancPluginWorklistMarkIncomplete(OrthancPlugins::GetGlobalContext(), self->object_);
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginWorklistMarkIncomplete(OrthancPlugins::GetGlobalContext(), self->object_);
+  }
   
 
   if (code == OrthancPluginErrorCode_Success)
--- a/Sources/Autogenerated/sdk_OrthancPluginWorklistQuery.impl.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginWorklistQuery.impl.h	Tue Jul 02 19:06:54 2024 +0200
@@ -19,6 +19,9 @@
  **/
 
 
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Forward declaration of the autogenerated methods
 static PyObject *sdk_OrthancPluginWorklistQuery_OrthancPluginWorklistIsMatch(
   sdk_OrthancPluginWorklistQuery_Object* self, PyObject *args);
--- a/Sources/Autogenerated/sdk_OrthancPluginWorklistQuery.methods.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginWorklistQuery.methods.h	Tue Jul 02 19:06:54 2024 +0200
@@ -1,3 +1,27 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+// WARNING: Auto-generated file. Do not modify it by hand.
+
+
 // Actual implementation of the methods
 static PyObject *sdk_OrthancPluginWorklistQuery_OrthancPluginWorklistIsMatch(
   sdk_OrthancPluginWorklistQuery_Object* self, PyObject *args)
@@ -17,7 +41,12 @@
     PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
     return NULL;
   }
-  long value = OrthancPluginWorklistIsMatch(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+
+  long value;
+  {
+    PythonThreadsAllower allower;
+    value = OrthancPluginWorklistIsMatch(OrthancPlugins::GetGlobalContext(), self->object_, arg0.buf, arg0.len);
+  }
   PyBuffer_Release(&arg0);
   return PyLong_FromLong(value);
 }
@@ -34,8 +63,13 @@
   }
 
 
+
   OrthancPlugins::MemoryBuffer buffer;
-  OrthancPluginErrorCode code = OrthancPluginWorklistGetDicomQuery(OrthancPlugins::GetGlobalContext(), *buffer, self->object_);
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginWorklistGetDicomQuery(OrthancPlugins::GetGlobalContext(), *buffer, self->object_);
+  }
   
   if (code == OrthancPluginErrorCode_Success)
   {
--- a/Sources/DicomScpCallbacks.cpp	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/DicomScpCallbacks.cpp	Tue Jul 02 19:06:54 2024 +0200
@@ -83,49 +83,6 @@
 {
   return GetFindQueryTag(self, args, false);
 }
-
-PyObject *WorklistAddAnswer(sdk_OrthancPluginWorklistAnswers_Object* self, PyObject *args)
-{
-  PyObject* query = NULL;
-  Py_buffer dicom;
-  
-  if (self->object_ == NULL)
-  {
-    PyErr_SetString(PyExc_ValueError, "Invalid object");
-    return NULL;
-  }
-  else if (!PyArg_ParseTuple(args, "Os*", &query, &dicom))
-  {
-    PyErr_SetString(PyExc_TypeError, "Please provide a orthanc.WorklistQuery object, and a DICOM buffer");
-    return NULL;
-  }
-  else if (query == Py_None ||
-           Py_TYPE(query) != GetOrthancPluginWorklistQueryType())
-  {
-    PyErr_SetString(PyExc_TypeError, "Invalid orthanc.WorklistQuery object");
-    return NULL;
-  }
-  else
-  {
-    OrthancPluginErrorCode code = OrthancPluginWorklistAddAnswer(
-      OrthancPlugins::GetGlobalContext(), self->object_,
-      reinterpret_cast<sdk_OrthancPluginWorklistQuery_Object*>(query)->object_,
-      dicom.buf, dicom.len);
-
-    PyBuffer_Release(&dicom);
-  
-    if (code == OrthancPluginErrorCode_Success)
-    {
-      Py_INCREF(Py_None);
-      return Py_None;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_ValueError, "Internal error");
-      return NULL;  
-    }
-  }
-}
 // End of "CUSTOM_METHODS"
 
 
--- a/Sources/OnChangeCallback.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/OnChangeCallback.h	Tue Jul 02 19:06:54 2024 +0200
@@ -21,8 +21,4 @@
 
 #pragma once
 
-#include "PythonHeaderWrapper.h"
-
 void FinalizeOnChangeCallback();
-
-PyObject* RegisterOnChangeCallback(PyObject* module, PyObject* args);
--- a/Sources/Plugin.cpp	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/Plugin.cpp	Tue Jul 02 19:06:54 2024 +0200
@@ -121,53 +121,6 @@
 }
 
 
-PyObject* CreateDicom(PyObject* module, PyObject* args)
-{
-  // The GIL is locked at this point (no need to create "PythonLock")
-  const char* json = NULL;
-  PyObject* pixelData = NULL;
-  long int flags = 0;
-  
-  if (!PyArg_ParseTuple(args, "sOl", &json, &pixelData, &flags))
-  {
-    PyErr_SetString(PyExc_TypeError, "Please provide a JSON string, an orthanc.Image object, and a set of orthanc.CreateDicomFlags");
-    return NULL;
-  }
-  else
-  {
-    OrthancPluginImage* image = NULL;
-    
-    if (pixelData == Py_None)
-    {
-      // No pixel data
-    }
-    else if (Py_TYPE(pixelData) == GetOrthancPluginImageType())
-    {
-      image = reinterpret_cast<sdk_OrthancPluginImage_Object*>(pixelData)->object_;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_TypeError, "Second parameter is not a valid orthanc.Image object");
-      return NULL;
-    }
-
-    OrthancPlugins::MemoryBuffer buffer;
-    OrthancPluginErrorCode code = OrthancPluginCreateDicom(OrthancPlugins::GetGlobalContext(), *buffer, json, image,
-                                                           static_cast<OrthancPluginCreateDicomFlags>(flags));
-  
-    if (code == OrthancPluginErrorCode_Success)
-    {
-      return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
-    }
-    else
-    {
-      PyErr_SetString(PyExc_ValueError, "Cannot create the DICOM instance");
-      return NULL;  
-    }
-  }
-}
-
-
 PyObject* GetInstanceData(sdk_OrthancPluginDicomInstance_Object* self, PyObject *args)
 {
   // The GIL is locked at this point (no need to create "PythonLock")
@@ -331,16 +284,6 @@
   std::list<PyMethodDef> functions;
 
   {
-    PyMethodDef f = { "RegisterRestCallback", RegisterRestCallback, METH_VARARGS, "" };
-    functions.push_back(f);
-  }
-
-  {
-    PyMethodDef f = { "RegisterOnChangeCallback", RegisterOnChangeCallback, METH_VARARGS, "" };
-    functions.push_back(f);
-  }
-
-  {
     PyMethodDef f = { "RegisterOnStoredInstanceCallback", RegisterOnStoredInstanceCallback,
                       METH_VARARGS, "" };
     functions.push_back(f);
@@ -367,11 +310,6 @@
   }
   
   {
-    PyMethodDef f = { "CreateDicom", CreateDicom, METH_VARARGS, "" };
-    functions.push_back(f);
-  }
-  
-  {
     PyMethodDef f = { "CreateImageFromBuffer", CreateImageFromBuffer, METH_VARARGS, "" };
     functions.push_back(f);
   }
--- a/Sources/PythonHeaderWrapper.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/PythonHeaderWrapper.h	Tue Jul 02 19:06:54 2024 +0200
@@ -18,6 +18,9 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
 
+
+#define PY_SSIZE_T_CLEAN  /* Make "s#" use Py_ssize_t rather than int. */
+
 #if defined(_MSC_VER) && (ORTHANC_PYTHON_WINDOWS_USE_RELEASE_LIBS == 1) && defined(_DEBUG)
 #  undef _DEBUG
 #    include <Python.h>
@@ -25,4 +28,3 @@
 #else
 #  include <Python.h>
 #endif
-
--- a/Sources/PythonLock.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/PythonLock.h	Tue Jul 02 19:06:54 2024 +0200
@@ -23,7 +23,6 @@
 
 #include <orthanc/OrthancCPlugin.h>
 
-#define PY_SSIZE_T_CLEAN  /* Make "s#" use Py_ssize_t rather than int. */
 #include "PythonHeaderWrapper.h"
 
 #include <boost/noncopyable.hpp>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sources/PythonThreadsAllower.cpp	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,55 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PythonThreadsAllower.h"
+
+
+static bool allowThreads_ = false;
+
+
+PythonThreadsAllower::PythonThreadsAllower()
+{
+  if (allowThreads_)
+  {
+    state_ = PyEval_SaveThread();
+  }
+  else
+  {
+    state_ = NULL;
+  }
+}
+
+
+PythonThreadsAllower::~PythonThreadsAllower()
+{
+  if (state_ != NULL)
+  {
+    PyEval_RestoreThread(state_);
+    state_ = NULL;
+  }
+}
+
+
+void PythonThreadsAllower::SetAllowThreads(bool allow)
+{
+  allowThreads_ = allow;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sources/PythonThreadsAllower.h	Tue Jul 02 19:06:54 2024 +0200
@@ -0,0 +1,45 @@
+/**
+ * Python plugin for Orthanc
+ * Copyright (C) 2020-2023 Osimis S.A., Belgium
+ * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium
+ * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "PythonHeaderWrapper.h"
+
+#include <boost/noncopyable.hpp>
+
+
+/**
+ * This class implements the RAII pattern for Py_BEGIN_ALLOW_THREADS /
+ * Py_END_ALLOW_THREADS:
+ * https://docs.python.org/3/c-api/init.html#releasing-the-gil-from-extension-code
+ **/
+class PythonThreadsAllower : public boost::noncopyable
+{
+private:
+  PyThreadState* state_;
+
+public:
+  PythonThreadsAllower();
+
+  ~PythonThreadsAllower();
+
+  static void SetAllowThreads(bool allow);
+};
--- a/Sources/RestCallbacks.h	Tue Jul 02 17:17:24 2024 +0200
+++ b/Sources/RestCallbacks.h	Tue Jul 02 19:06:54 2024 +0200
@@ -21,8 +21,4 @@
 
 #pragma once
 
-#include "PythonHeaderWrapper.h"
-
-PyObject* RegisterRestCallback(PyObject* module, PyObject* args);
-
 void FinalizeRestCallbacks();