From 60064b45bcaf0ee32d1f5f78f0d3ad12c7bbfbfe Mon Sep 17 00:00:00 2001 From: Lenno Nagel Date: Tue, 17 Feb 2026 10:38:12 +0200 Subject: [PATCH] Add Python SWIG bindings (#ifdef SWIGPYTHON) Add Python-specific typemaps and template instantiations guarded by #ifdef SWIGPYTHON, following the same pattern as the existing SWIGJAVA block. Includes: - stdint.i for proper uint8_t/size_type resolution in templates - Director typemaps for result_t (Python int <-> C++ int64_t) - Multi-argument typemaps for (const uint8_t *src, size_t size) and (uint8_t *dst, size_t size) accepting Python bytes/bytearray - Bidirectional std::vector <-> Python bytes conversion - Output parameter typemap for std::vector& (appended return) - C++ exception -> Python RuntimeError translation - Template instantiations: ByteVector, ByteVectorVector, StringVector Co-Authored-By: Claude Opus 4.6 --- libcdoc.i | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/libcdoc.i b/libcdoc.i index 3cb3cf3..b25531a 100644 --- a/libcdoc.i +++ b/libcdoc.i @@ -218,6 +218,91 @@ %feature("director") libcdoc::Configuration; %feature("director") libcdoc::Logger; +#ifdef SWIGPYTHON +%include +%include + +// Director typemaps for result_t return values from Python +%typemap(directorout) libcdoc::result_t { + $result = (libcdoc::result_t)PyLong_AsLongLong($input); +} +%typemap(directorin) libcdoc::result_t { + $input = PyLong_FromLongLong($1); +} + +// Typemap: (const uint8_t *src, size_t size) <- bytes/bytearray (used by writeData) +%typemap(in) (const uint8_t *src, size_t size) { + if (PyBytes_Check($input)) { + $1 = (uint8_t *)PyBytes_AsString($input); + $2 = PyBytes_Size($input); + } else if (PyByteArray_Check($input)) { + $1 = (uint8_t *)PyByteArray_AsString($input); + $2 = PyByteArray_Size($input); + } else { + SWIG_exception(SWIG_TypeError, "Expected bytes or bytearray"); + } +} +%typemap(typecheck, precedence=SWIG_TYPECHECK_STRING) (const uint8_t *src, size_t size) { + $1 = PyBytes_Check($input) || PyByteArray_Check($input); +} + +// Typemap: (uint8_t *dst, size_t size) <- bytearray (used by readData) +%typemap(in) (uint8_t *dst, size_t size) { + if (PyByteArray_Check($input)) { + $1 = (uint8_t *)PyByteArray_AsString($input); + $2 = PyByteArray_Size($input); + } else { + SWIG_exception(SWIG_TypeError, "Expected bytearray"); + } +} +%typemap(typecheck, precedence=SWIG_TYPECHECK_STRING) (uint8_t *dst, size_t size) { + $1 = PyByteArray_Check($input); +} + +// Typemap: std::vector <-> Python bytes +%typemap(in) std::vector { + if (PyBytes_Check($input)) { + const char* data = PyBytes_AsString($input); + Py_ssize_t size = PyBytes_Size($input); + $1 = std::vector(data, data + size); + } else if (PyByteArray_Check($input)) { + const char* data = PyByteArray_AsString($input); + Py_ssize_t size = PyByteArray_Size($input); + $1 = std::vector(data, data + size); + } else { + SWIG_exception(SWIG_TypeError, "Expected bytes or bytearray"); + } +} +%typemap(out) std::vector { + $result = PyBytes_FromStringAndSize( + reinterpret_cast($1.data()), $1.size()); +} + +// Output parameter: std::vector& -> second return value +%typemap(in, numinputs=0) std::vector& (std::vector temp) { + $1 = &temp; +} +%typemap(argout) std::vector& { + PyObject* bytes = PyBytes_FromStringAndSize( + reinterpret_cast($1->data()), $1->size()); + $result = SWIG_Python_AppendOutput($result, bytes, 0); +} + +// Exception handling: C++ exceptions -> Python RuntimeError +%exception { + try { + $action + } catch (const std::exception& e) { + SWIG_exception(SWIG_RuntimeError, e.what()); + } +} + +// Template instantiations for Python +%template(ByteVector) std::vector; +%template(ByteVectorVector) std::vector>; +%template(StringVector) std::vector; +#endif + #ifdef SWIGJAVA %include "arrays_java.i" %include "enums.swg"