diff --git a/msvscpp/pypff/pypff.vcproj b/msvscpp/pypff/pypff.vcproj
index 8f29ad60..afa5a636 100644
--- a/msvscpp/pypff/pypff.vcproj
+++ b/msvscpp/pypff/pypff.vcproj
@@ -233,6 +233,18 @@
RelativePath="..\..\pypff\pypff_message.c"
>
+
+
+
+
+
+
@@ -253,6 +265,10 @@
RelativePath="..\..\pypff\pypff_record_sets.c"
>
+
+
+
+
+
+
+
+
@@ -363,6 +391,10 @@
RelativePath="..\..\pypff\pypff_record_sets.h"
>
+
+
diff --git a/pypff/Makefile.am b/pypff/Makefile.am
index 330f0a39..3be45099 100644
--- a/pypff/Makefile.am
+++ b/pypff/Makefile.am
@@ -35,12 +35,16 @@ pypff_la_SOURCES = \
pypff_libclocale.h \
pypff_libpff.h \
pypff_message.c pypff_message.h \
+ pypff_message_store.c pypff_message_store.h \
+ pypff_multi_value.c pypff_multi_value.h \
+ pypff_name_to_id_map_entry.c pypff_name_to_id_map_entry.h \
pypff_python.h \
pypff_recipients.c pypff_recipients.h \
pypff_record_entry.c pypff_record_entry.h \
pypff_record_entries.c pypff_record_entries.h \
pypff_record_set.c pypff_record_set.h \
pypff_record_sets.c pypff_record_sets.h \
+ pypff_task.c pypff_task.h \
pypff_unused.h
pypff_la_LIBADD = \
diff --git a/pypff/pypff.c b/pypff/pypff.c
index 51623620..418708c8 100644
--- a/pypff/pypff.c
+++ b/pypff/pypff.c
@@ -39,12 +39,16 @@
#include "pypff_libcerror.h"
#include "pypff_libpff.h"
#include "pypff_message.h"
+#include "pypff_message_store.h"
+#include "pypff_multi_value.h"
+#include "pypff_name_to_id_map_entry.h"
#include "pypff_python.h"
#include "pypff_recipients.h"
#include "pypff_record_entries.h"
#include "pypff_record_entry.h"
#include "pypff_record_set.h"
#include "pypff_record_sets.h"
+#include "pypff_task.h"
#include "pypff_unused.h"
#if !defined( LIBPFF_HAVE_BFIO )
@@ -681,6 +685,23 @@ PyMODINIT_FUNC initpypff(
"item",
(PyObject *) &pypff_item_type_object );
+ /* Setup the message_store type object
+ */
+ pypff_message_store_type_object.tp_new = PyType_GenericNew;
+
+ if( PyType_Ready(
+ &pypff_message_store_type_object ) < 0 )
+ {
+ goto on_error;
+ }
+ Py_IncRef(
+ (PyObject *) &pypff_message_store_type_object );
+
+ PyModule_AddObject(
+ module,
+ "message_store",
+ (PyObject *) &pypff_message_store_type_object );
+
/* Setup the items type object
*/
pypff_items_type_object.tp_new = PyType_GenericNew;
@@ -715,6 +736,23 @@ PyMODINIT_FUNC initpypff(
"message",
(PyObject *) &pypff_message_type_object );
+ /* Setup the task type object
+ */
+ pypff_task_type_object.tp_new = PyType_GenericNew;
+
+ if( PyType_Ready(
+ &pypff_task_type_object ) < 0 )
+ {
+ goto on_error;
+ }
+ Py_IncRef(
+ (PyObject *) &pypff_task_type_object );
+
+ PyModule_AddObject(
+ module,
+ "task",
+ (PyObject *) &pypff_task_type_object );
+
/* Setup the recipients type object
*/
pypff_recipients_type_object.tp_new = PyType_GenericNew;
@@ -732,6 +770,40 @@ PyMODINIT_FUNC initpypff(
"recipients",
(PyObject *) &pypff_recipients_type_object );
+ /* Setup the multi_value type object
+ */
+ pypff_multi_value_type_object.tp_new = PyType_GenericNew;
+
+ if( PyType_Ready(
+ &pypff_multi_value_type_object ) < 0 )
+ {
+ goto on_error;
+ }
+ Py_IncRef(
+ (PyObject *) &pypff_multi_value_type_object );
+
+ PyModule_AddObject(
+ module,
+ "multi_value",
+ (PyObject *) &pypff_multi_value_type_object );
+
+ /* Setup the name_to_id_map_entry type object
+ */
+ pypff_name_to_id_map_entry_type_object.tp_new = PyType_GenericNew;
+
+ if( PyType_Ready(
+ &pypff_name_to_id_map_entry_type_object ) < 0 )
+ {
+ goto on_error;
+ }
+ Py_IncRef(
+ (PyObject *) &pypff_name_to_id_map_entry_type_object );
+
+ PyModule_AddObject(
+ module,
+ "name_to_id_map_entry",
+ (PyObject *) &pypff_name_to_id_map_entry_type_object );
+
/* Setup the record_entries type object
*/
pypff_record_entries_type_object.tp_new = PyType_GenericNew;
diff --git a/pypff/pypff_file.c b/pypff/pypff_file.c
index ef988338..789e1673 100644
--- a/pypff/pypff_file.c
+++ b/pypff/pypff_file.c
@@ -41,7 +41,10 @@
#include "pypff_libclocale.h"
#include "pypff_libpff.h"
#include "pypff_message.h"
+#include "pypff_message_store.h"
#include "pypff_python.h"
+#include "pypff_recipients.h"
+#include "pypff_task.h"
#include "pypff_unused.h"
#if !defined( LIBPFF_HAVE_BFIO )
@@ -1458,19 +1461,23 @@ PyTypeObject *pypff_file_get_item_type_object(
case LIBPFF_ITEM_TYPE_RSS_FEED:
case LIBPFF_ITEM_TYPE_SHARING:
case LIBPFF_ITEM_TYPE_SMS:
- case LIBPFF_ITEM_TYPE_TASK:
- case LIBPFF_ITEM_TYPE_TASK_REQUEST:
case LIBPFF_ITEM_TYPE_VOICEMAIL:
return( &pypff_message_type_object );
+ case LIBPFF_ITEM_TYPE_TASK:
+ case LIBPFF_ITEM_TYPE_TASK_REQUEST:
+ return( &pypff_task_type_object );
+
case LIBPFF_ITEM_TYPE_ATTACHMENT:
return( &pypff_attachment_type_object );
case LIBPFF_ITEM_TYPE_FOLDER:
return( &pypff_folder_type_object );
- case LIBPFF_ITEM_TYPE_ATTACHMENTS:
case LIBPFF_ITEM_TYPE_RECIPIENTS:
+ return( &pypff_recipients_type_object );
+
+ case LIBPFF_ITEM_TYPE_ATTACHMENTS:
case LIBPFF_ITEM_TYPE_SUB_ASSOCIATED_CONTENTS:
case LIBPFF_ITEM_TYPE_SUB_FOLDERS:
case LIBPFF_ITEM_TYPE_SUB_MESSAGES:
@@ -1562,7 +1569,6 @@ PyObject *pypff_file_get_message_store(
PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
{
PyObject *message_store_object = NULL;
- PyTypeObject *type_object = NULL;
libcerror_error_t *error = NULL;
libpff_item_t *message_store = NULL;
static char *function = "pypff_file_get_message_store";
@@ -1608,20 +1614,8 @@ PyObject *pypff_file_get_message_store(
return( Py_None );
}
- type_object = pypff_file_get_item_type_object(
- message_store );
-
- if( type_object == NULL )
- {
- PyErr_Format(
- PyExc_IOError,
- "%s: unable to retrieve message store type object.",
- function );
-
- goto on_error;
- }
message_store_object = pypff_item_new(
- type_object,
+ &pypff_message_store_type_object,
message_store,
(PyObject *) pypff_file );
diff --git a/pypff/pypff_item.c b/pypff/pypff_item.c
index 7819159f..03769b46 100644
--- a/pypff/pypff_item.c
+++ b/pypff/pypff_item.c
@@ -26,6 +26,7 @@
#include
#endif
+#include "pypff_attachment.h"
#include "pypff_error.h"
#include "pypff_folder.h"
#include "pypff_item.h"
@@ -34,8 +35,10 @@
#include "pypff_libpff.h"
#include "pypff_message.h"
#include "pypff_python.h"
+#include "pypff_recipients.h"
#include "pypff_record_set.h"
#include "pypff_record_sets.h"
+#include "pypff_task.h"
#include "pypff_unused.h"
PyMethodDef pypff_item_object_methods[] = {
@@ -887,17 +890,23 @@ PyTypeObject *pypff_item_get_item_type_object(
case LIBPFF_ITEM_TYPE_RSS_FEED:
case LIBPFF_ITEM_TYPE_SHARING:
case LIBPFF_ITEM_TYPE_SMS:
- case LIBPFF_ITEM_TYPE_TASK:
- case LIBPFF_ITEM_TYPE_TASK_REQUEST:
case LIBPFF_ITEM_TYPE_VOICEMAIL:
return( &pypff_message_type_object );
+ case LIBPFF_ITEM_TYPE_TASK:
+ case LIBPFF_ITEM_TYPE_TASK_REQUEST:
+ return( &pypff_task_type_object );
+
+ case LIBPFF_ITEM_TYPE_ATTACHMENT:
+ return( &pypff_attachment_type_object );
+
case LIBPFF_ITEM_TYPE_FOLDER:
return( &pypff_folder_type_object );
- case LIBPFF_ITEM_TYPE_ATTACHMENT:
- case LIBPFF_ITEM_TYPE_ATTACHMENTS:
case LIBPFF_ITEM_TYPE_RECIPIENTS:
+ return( &pypff_recipients_type_object );
+
+ case LIBPFF_ITEM_TYPE_ATTACHMENTS:
case LIBPFF_ITEM_TYPE_SUB_ASSOCIATED_CONTENTS:
case LIBPFF_ITEM_TYPE_SUB_FOLDERS:
case LIBPFF_ITEM_TYPE_SUB_MESSAGES:
diff --git a/pypff/pypff_message_store.c b/pypff/pypff_message_store.c
new file mode 100644
index 00000000..8bb99739
--- /dev/null
+++ b/pypff/pypff_message_store.c
@@ -0,0 +1,134 @@
+/*
+ * Python object wrapper of a libpff message store item
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include "pypff_item.h"
+#include "pypff_message_store.h"
+#include "pypff_python.h"
+
+PyMethodDef pypff_message_store_object_methods[] = {
+
+ /* Sentinel */
+ { NULL, NULL, 0, NULL }
+};
+
+PyGetSetDef pypff_message_store_object_get_set_definitions[] = {
+
+ /* Sentinel */
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+PyTypeObject pypff_message_store_type_object = {
+ PyVarObject_HEAD_INIT( NULL, 0 )
+
+ /* tp_name */
+ "pypff.message_store",
+ /* tp_basicsize */
+ sizeof( pypff_item_t ),
+ /* tp_itemsize */
+ 0,
+ /* tp_dealloc */
+ 0,
+ /* tp_print */
+ 0,
+ /* tp_getattr */
+ 0,
+ /* tp_setattr */
+ 0,
+ /* tp_compare */
+ 0,
+ /* tp_repr */
+ 0,
+ /* tp_as_number */
+ 0,
+ /* tp_as_sequence */
+ 0,
+ /* tp_as_mapping */
+ 0,
+ /* tp_hash */
+ 0,
+ /* tp_call */
+ 0,
+ /* tp_str */
+ 0,
+ /* tp_getattro */
+ 0,
+ /* tp_setattro */
+ 0,
+ /* tp_as_buffer */
+ 0,
+ /* tp_flags */
+ Py_TPFLAGS_DEFAULT,
+ /* tp_doc */
+ "pypff message store object (wraps libpff_item_t)",
+ /* tp_traverse */
+ 0,
+ /* tp_clear */
+ 0,
+ /* tp_richcompare */
+ 0,
+ /* tp_weaklistoffset */
+ 0,
+ /* tp_iter */
+ 0,
+ /* tp_iternext */
+ 0,
+ /* tp_methods */
+ pypff_message_store_object_methods,
+ /* tp_members */
+ 0,
+ /* tp_getset */
+ pypff_message_store_object_get_set_definitions,
+ /* tp_base */
+ &pypff_item_type_object,
+ /* tp_dict */
+ 0,
+ /* tp_descr_get */
+ 0,
+ /* tp_descr_set */
+ 0,
+ /* tp_dictoffset */
+ 0,
+ /* tp_init */
+ 0,
+ /* tp_alloc */
+ 0,
+ /* tp_new */
+ 0,
+ /* tp_free */
+ 0,
+ /* tp_is_gc */
+ 0,
+ /* tp_bases */
+ NULL,
+ /* tp_mro */
+ NULL,
+ /* tp_cache */
+ NULL,
+ /* tp_subclasses */
+ NULL,
+ /* tp_weaklist */
+ NULL,
+ /* tp_del */
+ 0
+};
diff --git a/pypff/pypff_message_store.h b/pypff/pypff_message_store.h
new file mode 100644
index 00000000..bed195a2
--- /dev/null
+++ b/pypff/pypff_message_store.h
@@ -0,0 +1,42 @@
+/*
+ * Python object wrapper of a libpff message store item
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#if !defined( _PYPFF_MESSAGE_STORE_H )
+#define _PYPFF_MESSAGE_STORE_H
+
+#include
+#include
+
+#include "pypff_item.h"
+#include "pypff_python.h"
+
+#if defined( __cplusplus )
+extern "C" {
+#endif
+
+extern PyMethodDef pypff_message_store_object_methods[];
+extern PyTypeObject pypff_message_store_type_object;
+
+#if defined( __cplusplus )
+}
+#endif
+
+#endif /* !defined( _PYPFF_MESSAGE_STORE_H ) */
diff --git a/pypff/pypff_multi_value.c b/pypff/pypff_multi_value.c
new file mode 100644
index 00000000..89738606
--- /dev/null
+++ b/pypff/pypff_multi_value.c
@@ -0,0 +1,1091 @@
+/*
+ * Python object wrapper of libpff_multi_value_t
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#if defined( HAVE_STDLIB_H ) || defined( HAVE_WINAPI )
+#include
+#endif
+
+#include "pypff_datetime.h"
+#include "pypff_error.h"
+#include "pypff_integer.h"
+#include "pypff_libcerror.h"
+#include "pypff_libpff.h"
+#include "pypff_multi_value.h"
+#include "pypff_python.h"
+#include "pypff_unused.h"
+
+PyMethodDef pypff_multi_value_object_methods[] = {
+
+ { "get_number_of_values",
+ (PyCFunction) pypff_multi_value_get_number_of_values,
+ METH_NOARGS,
+ "get_number_of_values() -> Integer\n"
+ "\n"
+ "Retrieves the number of values." },
+
+ { "get_value_type",
+ (PyCFunction) pypff_multi_value_get_value_type,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_value_type(value_index) -> Integer\n"
+ "\n"
+ "Retrieves the type of the value specified by the index." },
+
+ { "get_value",
+ (PyCFunction) pypff_multi_value_get_value,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_value(value_index) -> Bytes or None\n"
+ "\n"
+ "Retrieves the value specified by the index as bytes." },
+
+ { "get_value_as_integer",
+ (PyCFunction) pypff_multi_value_get_value_as_integer,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_value_as_integer(value_index) -> Integer\n"
+ "\n"
+ "Retrieves the value specified by the index as an integer." },
+
+ { "get_value_as_datetime",
+ (PyCFunction) pypff_multi_value_get_value_as_datetime,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_value_as_datetime(value_index) -> Datetime\n"
+ "\n"
+ "Retrieves the value specified by the index as a datetime object." },
+
+ { "get_value_as_string",
+ (PyCFunction) pypff_multi_value_get_value_as_string,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_value_as_string(value_index) -> Unicode string or None\n"
+ "\n"
+ "Retrieves the value specified by the index as a string." },
+
+ { "get_value_as_binary_data",
+ (PyCFunction) pypff_multi_value_get_value_as_binary_data,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_value_as_binary_data(value_index) -> Bytes or None\n"
+ "\n"
+ "Retrieves the value specified by the index as binary data." },
+
+ { "get_value_as_guid",
+ (PyCFunction) pypff_multi_value_get_value_as_guid,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_value_as_guid(value_index) -> Bytes\n"
+ "\n"
+ "Retrieves the value specified by the index as a GUID." },
+
+ /* Sentinel */
+ { NULL, NULL, 0, NULL }
+};
+
+PyGetSetDef pypff_multi_value_object_get_set_definitions[] = {
+
+ { "number_of_values",
+ (getter) pypff_multi_value_get_number_of_values,
+ (setter) 0,
+ "The number of values.",
+ NULL },
+
+ /* Sentinel */
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+PyTypeObject pypff_multi_value_type_object = {
+ PyVarObject_HEAD_INIT( NULL, 0 )
+
+ /* tp_name */
+ "pypff.multi_value",
+ /* tp_basicsize */
+ sizeof( pypff_multi_value_t ),
+ /* tp_itemsize */
+ 0,
+ /* tp_dealloc */
+ (destructor) pypff_multi_value_free,
+ /* tp_print */
+ 0,
+ /* tp_getattr */
+ 0,
+ /* tp_setattr */
+ 0,
+ /* tp_compare */
+ 0,
+ /* tp_repr */
+ 0,
+ /* tp_as_number */
+ 0,
+ /* tp_as_sequence */
+ 0,
+ /* tp_as_mapping */
+ 0,
+ /* tp_hash */
+ 0,
+ /* tp_call */
+ 0,
+ /* tp_str */
+ 0,
+ /* tp_getattro */
+ 0,
+ /* tp_setattro */
+ 0,
+ /* tp_as_buffer */
+ 0,
+ /* tp_flags */
+ Py_TPFLAGS_DEFAULT,
+ /* tp_doc */
+ "pypff multi value object (wraps libpff_multi_value_t)",
+ /* tp_traverse */
+ 0,
+ /* tp_clear */
+ 0,
+ /* tp_richcompare */
+ 0,
+ /* tp_weaklistoffset */
+ 0,
+ /* tp_iter */
+ 0,
+ /* tp_iternext */
+ 0,
+ /* tp_methods */
+ pypff_multi_value_object_methods,
+ /* tp_members */
+ 0,
+ /* tp_getset */
+ pypff_multi_value_object_get_set_definitions,
+ /* tp_base */
+ 0,
+ /* tp_dict */
+ 0,
+ /* tp_descr_get */
+ 0,
+ /* tp_descr_set */
+ 0,
+ /* tp_dictoffset */
+ 0,
+ /* tp_init */
+ (initproc) pypff_multi_value_init,
+ /* tp_alloc */
+ 0,
+ /* tp_new */
+ 0,
+ /* tp_free */
+ 0,
+ /* tp_is_gc */
+ 0,
+ /* tp_bases */
+ NULL,
+ /* tp_mro */
+ NULL,
+ /* tp_cache */
+ NULL,
+ /* tp_subclasses */
+ NULL,
+ /* tp_weaklist */
+ NULL,
+ /* tp_del */
+ 0
+};
+
+/* Creates a new multi value object
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_new(
+ libpff_multi_value_t *multi_value,
+ PyObject *parent_object )
+{
+ pypff_multi_value_t *pypff_multi_value = NULL;
+ static char *function = "pypff_multi_value_new";
+
+ if( multi_value == NULL )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ pypff_multi_value = PyObject_New(
+ struct pypff_multi_value,
+ &pypff_multi_value_type_object );
+
+ if( pypff_multi_value == NULL )
+ {
+ PyErr_Format(
+ PyExc_MemoryError,
+ "%s: unable to initialize multi value.",
+ function );
+
+ return( NULL );
+ }
+ pypff_multi_value->multi_value = multi_value;
+ pypff_multi_value->parent_object = parent_object;
+
+ if( parent_object != NULL )
+ {
+ Py_IncRef(
+ parent_object );
+ }
+ return( (PyObject *) pypff_multi_value );
+}
+
+/* Initializes a multi value object
+ * Returns 0 if successful or -1 on error
+ */
+int pypff_multi_value_init(
+ pypff_multi_value_t *pypff_multi_value )
+{
+ static char *function = "pypff_multi_value_init";
+
+ if( pypff_multi_value == NULL )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( -1 );
+ }
+ pypff_multi_value->multi_value = NULL;
+ pypff_multi_value->parent_object = NULL;
+
+ return( 0 );
+}
+
+/* Frees a multi value object
+ */
+void pypff_multi_value_free(
+ pypff_multi_value_t *pypff_multi_value )
+{
+ struct _typeobject *ob_type = NULL;
+ libcerror_error_t *error = NULL;
+ static char *function = "pypff_multi_value_free";
+ int result = 0;
+
+ if( pypff_multi_value == NULL )
+ {
+ return;
+ }
+ ob_type = Py_TYPE(
+ pypff_multi_value );
+
+ if( pypff_multi_value->multi_value != NULL )
+ {
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_free(
+ &( pypff_multi_value->multi_value ),
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to free libpff multi value.",
+ function );
+
+ libcerror_error_free(
+ &error );
+ }
+ }
+ if( pypff_multi_value->parent_object != NULL )
+ {
+ Py_DecRef(
+ pypff_multi_value->parent_object );
+ }
+ if( ( ob_type != NULL )
+ && ( ob_type->tp_free != NULL ) )
+ {
+ ob_type->tp_free(
+ (PyObject *) pypff_multi_value );
+ }
+}
+
+/* Retrieves the number of values
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_number_of_values(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
+{
+ PyObject *integer_object = NULL;
+ libcerror_error_t *error = NULL;
+ static char *function = "pypff_multi_value_get_number_of_values";
+ int number_of_values = 0;
+ int result = 0;
+
+ PYPFF_UNREFERENCED_PARAMETER( arguments )
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_number_of_values(
+ pypff_multi_value->multi_value,
+ &number_of_values,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve number of values.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+#if PY_MAJOR_VERSION >= 3
+ integer_object = PyLong_FromLong(
+ (long) number_of_values );
+#else
+ integer_object = PyInt_FromLong(
+ (long) number_of_values );
+#endif
+ return( integer_object );
+}
+
+/* Retrieves the type of a specific value
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_value_type(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *integer_object = NULL;
+ libcerror_error_t *error = NULL;
+ uint8_t *value_data = NULL;
+ static char *function = "pypff_multi_value_get_value_type";
+ static char *keyword_list[] = { "value_index", NULL };
+ size_t value_data_size = 0;
+ uint32_t value_type = 0;
+ int value_index = 0;
+ int result = 0;
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &value_index ) == 0 )
+ {
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value(
+ pypff_multi_value->multi_value,
+ value_index,
+ &value_type,
+ &value_data,
+ &value_data_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d type.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ integer_object = pypff_integer_unsigned_new_from_64bit(
+ (uint64_t) value_type );
+
+ return( integer_object );
+}
+
+/* Retrieves a specific value as bytes
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_value(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *bytes_object = NULL;
+ libcerror_error_t *error = NULL;
+ uint8_t *value_data = NULL;
+ static char *function = "pypff_multi_value_get_value";
+ static char *keyword_list[] = { "value_index", NULL };
+ size_t value_data_size = 0;
+ uint32_t value_type = 0;
+ int value_index = 0;
+ int result = 0;
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &value_index ) == 0 )
+ {
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value(
+ pypff_multi_value->multi_value,
+ value_index,
+ &value_type,
+ &value_data,
+ &value_data_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( ( value_data == NULL )
+ || ( value_data_size == 0 ) )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ bytes_object = PyBytes_FromStringAndSize(
+ (char *) value_data,
+ (Py_ssize_t) value_data_size );
+
+ return( bytes_object );
+}
+
+/* Retrieves a specific value as an integer
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_value_as_integer(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *integer_object = NULL;
+ libcerror_error_t *error = NULL;
+ uint8_t *value_data = NULL;
+ static char *function = "pypff_multi_value_get_value_as_integer";
+ static char *keyword_list[] = { "value_index", NULL };
+ size_t value_data_size = 0;
+ uint64_t value_64bit = 0;
+ uint32_t value_32bit = 0;
+ uint32_t value_type = 0;
+ int value_index = 0;
+ int result = 0;
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &value_index ) == 0 )
+ {
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value(
+ pypff_multi_value->multi_value,
+ value_index,
+ &value_type,
+ &value_data,
+ &value_data_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d type.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ switch( value_type )
+ {
+ case LIBPFF_VALUE_TYPE_INTEGER_16BIT_SIGNED:
+ case LIBPFF_VALUE_TYPE_INTEGER_32BIT_SIGNED:
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_32bit(
+ pypff_multi_value->multi_value,
+ value_index,
+ &value_32bit,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+#if PY_MAJOR_VERSION >= 3
+ if( value_type == LIBPFF_VALUE_TYPE_INTEGER_16BIT_SIGNED )
+ {
+ integer_object = PyLong_FromLong(
+ (long) ( (int16_t) value_32bit ) );
+ }
+ else
+ {
+ integer_object = PyLong_FromLong(
+ (long) ( (int32_t) value_32bit ) );
+ }
+#else
+ if( value_type == LIBPFF_VALUE_TYPE_INTEGER_16BIT_SIGNED )
+ {
+ integer_object = PyInt_FromLong(
+ (long) ( (int16_t) value_32bit ) );
+ }
+ else
+ {
+ integer_object = PyInt_FromLong(
+ (long) ( (int32_t) value_32bit ) );
+ }
+#endif
+ break;
+
+ case LIBPFF_VALUE_TYPE_INTEGER_64BIT_SIGNED:
+ case LIBPFF_VALUE_TYPE_FILETIME:
+ case LIBPFF_VALUE_TYPE_FLOATINGTIME:
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_64bit(
+ pypff_multi_value->multi_value,
+ value_index,
+ &value_64bit,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( value_type == LIBPFF_VALUE_TYPE_INTEGER_64BIT_SIGNED )
+ {
+ integer_object = pypff_integer_signed_new_from_64bit(
+ (int64_t) value_64bit );
+ }
+ else
+ {
+ integer_object = pypff_integer_unsigned_new_from_64bit(
+ value_64bit );
+ }
+ break;
+
+ default:
+ PyErr_Format(
+ PyExc_IOError,
+ "%s: value is not an integer type.",
+ function );
+
+ return( NULL );
+ }
+ if( result != 1 )
+ {
+ Py_XDECREF(
+ integer_object );
+
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d as an integer.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ return( integer_object );
+}
+
+/* Retrieves a specific value as a datetime object
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_value_as_datetime(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *datetime_object = NULL;
+ libcerror_error_t *error = NULL;
+ uint8_t *value_data = NULL;
+ static char *function = "pypff_multi_value_get_value_as_datetime";
+ static char *keyword_list[] = { "value_index", NULL };
+ size_t value_data_size = 0;
+ uint64_t filetime = 0;
+ uint32_t value_type = 0;
+ int value_index = 0;
+ int result = 0;
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &value_index ) == 0 )
+ {
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value(
+ pypff_multi_value->multi_value,
+ value_index,
+ &value_type,
+ &value_data,
+ &value_data_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d type.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( value_type != LIBPFF_VALUE_TYPE_FILETIME )
+ {
+ PyErr_Format(
+ PyExc_IOError,
+ "%s: value is not a datetime type.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_filetime(
+ pypff_multi_value->multi_value,
+ value_index,
+ &filetime,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d as a datetime.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ datetime_object = pypff_datetime_new_from_filetime(
+ filetime );
+
+ return( datetime_object );
+}
+
+/* Retrieves a specific value as a string
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_value_as_string(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *string_object = NULL;
+ libcerror_error_t *error = NULL;
+ char *utf8_string = NULL;
+ static char *function = "pypff_multi_value_get_value_as_string";
+ static char *keyword_list[] = { "value_index", NULL };
+ size_t utf8_string_size = 0;
+ int value_index = 0;
+ int result = 0;
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &value_index ) == 0 )
+ {
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_utf8_string_size(
+ pypff_multi_value->multi_value,
+ value_index,
+ &utf8_string_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result == -1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to determine size of value: %d as UTF-8 string.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( ( result == 0 )
+ || ( utf8_string_size == 0 ) )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ utf8_string = (char *) PyMem_Malloc(
+ sizeof( char ) * utf8_string_size );
+
+ if( utf8_string == NULL )
+ {
+ PyErr_Format(
+ PyExc_MemoryError,
+ "%s: unable to create UTF-8 string.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_utf8_string(
+ pypff_multi_value->multi_value,
+ value_index,
+ (uint8_t *) utf8_string,
+ utf8_string_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d as UTF-8 string.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ PyMem_Free(
+ utf8_string );
+
+ return( NULL );
+ }
+ string_object = PyUnicode_DecodeUTF8(
+ utf8_string,
+ (Py_ssize_t) utf8_string_size - 1,
+ NULL );
+
+ PyMem_Free(
+ utf8_string );
+
+ return( string_object );
+}
+
+/* Retrieves a specific value as binary data
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_value_as_binary_data(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *bytes_object = NULL;
+ libcerror_error_t *error = NULL;
+ uint8_t *binary_data = NULL;
+ static char *function = "pypff_multi_value_get_value_as_binary_data";
+ static char *keyword_list[] = { "value_index", NULL };
+ size_t binary_data_size = 0;
+ int value_index = 0;
+ int result = 0;
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &value_index ) == 0 )
+ {
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_binary_data_size(
+ pypff_multi_value->multi_value,
+ value_index,
+ &binary_data_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result == -1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to determine size of value: %d as binary data.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( ( result == 0 )
+ || ( binary_data_size == 0 ) )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ binary_data = (uint8_t *) PyMem_Malloc(
+ sizeof( uint8_t ) * binary_data_size );
+
+ if( binary_data == NULL )
+ {
+ PyErr_Format(
+ PyExc_MemoryError,
+ "%s: unable to create binary data.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_binary_data(
+ pypff_multi_value->multi_value,
+ value_index,
+ binary_data,
+ binary_data_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d as binary data.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ PyMem_Free(
+ binary_data );
+
+ return( NULL );
+ }
+ bytes_object = PyBytes_FromStringAndSize(
+ (char *) binary_data,
+ (Py_ssize_t) binary_data_size );
+
+ PyMem_Free(
+ binary_data );
+
+ return( bytes_object );
+}
+
+/* Retrieves a specific value as a GUID
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_multi_value_get_value_as_guid(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *bytes_object = NULL;
+ libcerror_error_t *error = NULL;
+ static char *function = "pypff_multi_value_get_value_as_guid";
+ static char *keyword_list[] = { "value_index", NULL };
+ uint8_t guid[ 16 ];
+ int value_index = 0;
+ int result = 0;
+
+ if( ( pypff_multi_value == NULL )
+ || ( pypff_multi_value->multi_value == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid multi value.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &value_index ) == 0 )
+ {
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_multi_value_get_value_guid(
+ pypff_multi_value->multi_value,
+ value_index,
+ guid,
+ 16,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value: %d as a GUID.",
+ function,
+ value_index );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ bytes_object = PyBytes_FromStringAndSize(
+ (char *) guid,
+ 16 );
+
+ return( bytes_object );
+}
diff --git a/pypff/pypff_multi_value.h b/pypff/pypff_multi_value.h
new file mode 100644
index 00000000..06943143
--- /dev/null
+++ b/pypff/pypff_multi_value.h
@@ -0,0 +1,108 @@
+/*
+ * Python object wrapper of libpff_multi_value_t
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#if !defined( _PYPFF_MULTI_VALUE_H )
+#define _PYPFF_MULTI_VALUE_H
+
+#include
+#include
+
+#include "pypff_libpff.h"
+#include "pypff_python.h"
+
+#if defined( __cplusplus )
+extern "C" {
+#endif
+
+typedef struct pypff_multi_value pypff_multi_value_t;
+
+struct pypff_multi_value
+{
+ /* Python object initialization
+ */
+ PyObject_HEAD
+
+ /* The libpff multi value
+ */
+ libpff_multi_value_t *multi_value;
+
+ /* The parent object
+ */
+ PyObject *parent_object;
+};
+
+extern PyMethodDef pypff_multi_value_object_methods[];
+extern PyTypeObject pypff_multi_value_type_object;
+
+PyObject *pypff_multi_value_new(
+ libpff_multi_value_t *multi_value,
+ PyObject *parent_object );
+
+int pypff_multi_value_init(
+ pypff_multi_value_t *pypff_multi_value );
+
+void pypff_multi_value_free(
+ pypff_multi_value_t *pypff_multi_value );
+
+PyObject *pypff_multi_value_get_number_of_values(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments );
+
+PyObject *pypff_multi_value_get_value_type(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords );
+
+PyObject *pypff_multi_value_get_value(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords );
+
+PyObject *pypff_multi_value_get_value_as_integer(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords );
+
+PyObject *pypff_multi_value_get_value_as_datetime(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords );
+
+PyObject *pypff_multi_value_get_value_as_string(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords );
+
+PyObject *pypff_multi_value_get_value_as_binary_data(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords );
+
+PyObject *pypff_multi_value_get_value_as_guid(
+ pypff_multi_value_t *pypff_multi_value,
+ PyObject *arguments,
+ PyObject *keywords );
+
+#if defined( __cplusplus )
+}
+#endif
+
+#endif /* !defined( _PYPFF_MULTI_VALUE_H ) */
diff --git a/pypff/pypff_name_to_id_map_entry.c b/pypff/pypff_name_to_id_map_entry.c
new file mode 100644
index 00000000..0bd3be83
--- /dev/null
+++ b/pypff/pypff_name_to_id_map_entry.c
@@ -0,0 +1,616 @@
+/*
+ * Python object wrapper of libpff_name_to_id_map_entry_t
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#if defined( HAVE_STDLIB_H ) || defined( HAVE_WINAPI )
+#include
+#endif
+
+#include "pypff_error.h"
+#include "pypff_integer.h"
+#include "pypff_libcerror.h"
+#include "pypff_libpff.h"
+#include "pypff_name_to_id_map_entry.h"
+#include "pypff_python.h"
+#include "pypff_unused.h"
+
+PyMethodDef pypff_name_to_id_map_entry_object_methods[] = {
+
+ { "get_type",
+ (PyCFunction) pypff_name_to_id_map_entry_get_type,
+ METH_NOARGS,
+ "get_type() -> Integer\n"
+ "\n"
+ "Retrieves the name to ID map entry type." },
+
+ { "get_number",
+ (PyCFunction) pypff_name_to_id_map_entry_get_number,
+ METH_NOARGS,
+ "get_number() -> Integer or None\n"
+ "\n"
+ "Retrieves the numeric name value." },
+
+ { "get_string",
+ (PyCFunction) pypff_name_to_id_map_entry_get_string,
+ METH_NOARGS,
+ "get_string() -> Unicode string or None\n"
+ "\n"
+ "Retrieves the string name value." },
+
+ { "get_guid",
+ (PyCFunction) pypff_name_to_id_map_entry_get_guid,
+ METH_NOARGS,
+ "get_guid() -> Bytes\n"
+ "\n"
+ "Retrieves the property-set GUID." },
+
+ /* Sentinel */
+ { NULL, NULL, 0, NULL }
+};
+
+PyGetSetDef pypff_name_to_id_map_entry_object_get_set_definitions[] = {
+
+ { "type",
+ (getter) pypff_name_to_id_map_entry_get_type,
+ (setter) 0,
+ "The name to ID map entry type.",
+ NULL },
+
+ { "number",
+ (getter) pypff_name_to_id_map_entry_get_number,
+ (setter) 0,
+ "The numeric name value.",
+ NULL },
+
+ { "string",
+ (getter) pypff_name_to_id_map_entry_get_string,
+ (setter) 0,
+ "The string name value.",
+ NULL },
+
+ { "guid",
+ (getter) pypff_name_to_id_map_entry_get_guid,
+ (setter) 0,
+ "The property-set GUID.",
+ NULL },
+
+ /* Sentinel */
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+PyTypeObject pypff_name_to_id_map_entry_type_object = {
+ PyVarObject_HEAD_INIT( NULL, 0 )
+
+ /* tp_name */
+ "pypff.name_to_id_map_entry",
+ /* tp_basicsize */
+ sizeof( pypff_name_to_id_map_entry_t ),
+ /* tp_itemsize */
+ 0,
+ /* tp_dealloc */
+ (destructor) pypff_name_to_id_map_entry_free,
+ /* tp_print */
+ 0,
+ /* tp_getattr */
+ 0,
+ /* tp_setattr */
+ 0,
+ /* tp_compare */
+ 0,
+ /* tp_repr */
+ 0,
+ /* tp_as_number */
+ 0,
+ /* tp_as_sequence */
+ 0,
+ /* tp_as_mapping */
+ 0,
+ /* tp_hash */
+ 0,
+ /* tp_call */
+ 0,
+ /* tp_str */
+ 0,
+ /* tp_getattro */
+ 0,
+ /* tp_setattro */
+ 0,
+ /* tp_as_buffer */
+ 0,
+ /* tp_flags */
+ Py_TPFLAGS_DEFAULT,
+ /* tp_doc */
+ "pypff name to ID map entry object (wraps libpff_name_to_id_map_entry_t)",
+ /* tp_traverse */
+ 0,
+ /* tp_clear */
+ 0,
+ /* tp_richcompare */
+ 0,
+ /* tp_weaklistoffset */
+ 0,
+ /* tp_iter */
+ 0,
+ /* tp_iternext */
+ 0,
+ /* tp_methods */
+ pypff_name_to_id_map_entry_object_methods,
+ /* tp_members */
+ 0,
+ /* tp_getset */
+ pypff_name_to_id_map_entry_object_get_set_definitions,
+ /* tp_base */
+ 0,
+ /* tp_dict */
+ 0,
+ /* tp_descr_get */
+ 0,
+ /* tp_descr_set */
+ 0,
+ /* tp_dictoffset */
+ 0,
+ /* tp_init */
+ (initproc) pypff_name_to_id_map_entry_init,
+ /* tp_alloc */
+ 0,
+ /* tp_new */
+ 0,
+ /* tp_free */
+ 0,
+ /* tp_is_gc */
+ 0,
+ /* tp_bases */
+ NULL,
+ /* tp_mro */
+ NULL,
+ /* tp_cache */
+ NULL,
+ /* tp_subclasses */
+ NULL,
+ /* tp_weaklist */
+ NULL,
+ /* tp_del */
+ 0
+};
+
+/* Creates a new name to ID map entry object
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_name_to_id_map_entry_new(
+ libpff_name_to_id_map_entry_t *name_to_id_map_entry,
+ PyObject *parent_object )
+{
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry = NULL;
+ static char *function = "pypff_name_to_id_map_entry_new";
+
+ if( name_to_id_map_entry == NULL )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid name to ID map entry.",
+ function );
+
+ return( NULL );
+ }
+ pypff_name_to_id_map_entry = PyObject_New(
+ struct pypff_name_to_id_map_entry,
+ &pypff_name_to_id_map_entry_type_object );
+
+ if( pypff_name_to_id_map_entry == NULL )
+ {
+ PyErr_Format(
+ PyExc_MemoryError,
+ "%s: unable to initialize name to ID map entry.",
+ function );
+
+ return( NULL );
+ }
+ pypff_name_to_id_map_entry->name_to_id_map_entry = name_to_id_map_entry;
+ pypff_name_to_id_map_entry->parent_object = parent_object;
+
+ if( parent_object != NULL )
+ {
+ Py_IncRef(
+ parent_object );
+ }
+ return( (PyObject *) pypff_name_to_id_map_entry );
+}
+
+/* Initializes a name to ID map entry object
+ * Returns 0 if successful or -1 on error
+ */
+int pypff_name_to_id_map_entry_init(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry )
+{
+ static char *function = "pypff_name_to_id_map_entry_init";
+
+ if( pypff_name_to_id_map_entry == NULL )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid name to ID map entry.",
+ function );
+
+ return( -1 );
+ }
+ pypff_name_to_id_map_entry->name_to_id_map_entry = NULL;
+ pypff_name_to_id_map_entry->parent_object = NULL;
+
+ return( 0 );
+}
+
+/* Frees a name to ID map entry object
+ */
+void pypff_name_to_id_map_entry_free(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry )
+{
+ struct _typeobject *ob_type = NULL;
+
+ if( pypff_name_to_id_map_entry == NULL )
+ {
+ return;
+ }
+ ob_type = Py_TYPE(
+ pypff_name_to_id_map_entry );
+
+ if( pypff_name_to_id_map_entry->parent_object != NULL )
+ {
+ Py_DecRef(
+ pypff_name_to_id_map_entry->parent_object );
+ }
+ if( ( ob_type != NULL )
+ && ( ob_type->tp_free != NULL ) )
+ {
+ ob_type->tp_free(
+ (PyObject *) pypff_name_to_id_map_entry );
+ }
+}
+
+/* Retrieves the entry type
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_name_to_id_map_entry_get_type(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
+{
+ PyObject *integer_object = NULL;
+ libcerror_error_t *error = NULL;
+ static char *function = "pypff_name_to_id_map_entry_get_type";
+ uint8_t entry_type = 0;
+ int result = 0;
+
+ PYPFF_UNREFERENCED_PARAMETER( arguments )
+
+ if( ( pypff_name_to_id_map_entry == NULL )
+ || ( pypff_name_to_id_map_entry->name_to_id_map_entry == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid name to ID map entry.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_name_to_id_map_entry_get_type(
+ pypff_name_to_id_map_entry->name_to_id_map_entry,
+ &entry_type,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve entry type.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+#if PY_MAJOR_VERSION >= 3
+ integer_object = PyLong_FromLong(
+ (long) entry_type );
+#else
+ integer_object = PyInt_FromLong(
+ (long) entry_type );
+#endif
+ return( integer_object );
+}
+
+/* Retrieves the numeric name value
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_name_to_id_map_entry_get_number(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
+{
+ PyObject *integer_object = NULL;
+ libcerror_error_t *error = NULL;
+ static char *function = "pypff_name_to_id_map_entry_get_number";
+ uint32_t number = 0;
+ uint8_t entry_type = 0;
+ int result = 0;
+
+ PYPFF_UNREFERENCED_PARAMETER( arguments )
+
+ if( ( pypff_name_to_id_map_entry == NULL )
+ || ( pypff_name_to_id_map_entry->name_to_id_map_entry == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid name to ID map entry.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_name_to_id_map_entry_get_type(
+ pypff_name_to_id_map_entry->name_to_id_map_entry,
+ &entry_type,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve entry type.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( entry_type != LIBPFF_NAME_TO_ID_MAP_ENTRY_TYPE_NUMERIC )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_name_to_id_map_entry_get_number(
+ pypff_name_to_id_map_entry->name_to_id_map_entry,
+ &number,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve numeric name value.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ integer_object = pypff_integer_unsigned_new_from_64bit(
+ (uint64_t) number );
+
+ return( integer_object );
+}
+
+/* Retrieves the string name value
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_name_to_id_map_entry_get_string(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
+{
+ PyObject *string_object = NULL;
+ libcerror_error_t *error = NULL;
+ char *utf8_string = NULL;
+ static char *function = "pypff_name_to_id_map_entry_get_string";
+ size_t utf8_string_size = 0;
+ uint8_t entry_type = 0;
+ int result = 0;
+
+ PYPFF_UNREFERENCED_PARAMETER( arguments )
+
+ if( ( pypff_name_to_id_map_entry == NULL )
+ || ( pypff_name_to_id_map_entry->name_to_id_map_entry == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid name to ID map entry.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_name_to_id_map_entry_get_type(
+ pypff_name_to_id_map_entry->name_to_id_map_entry,
+ &entry_type,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve entry type.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( entry_type != LIBPFF_NAME_TO_ID_MAP_ENTRY_TYPE_STRING )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_name_to_id_map_entry_get_utf8_string_size(
+ pypff_name_to_id_map_entry->name_to_id_map_entry,
+ &utf8_string_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to determine size of string name value.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( utf8_string_size == 0 )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ utf8_string = (char *) PyMem_Malloc(
+ sizeof( char ) * utf8_string_size );
+
+ if( utf8_string == NULL )
+ {
+ PyErr_Format(
+ PyExc_MemoryError,
+ "%s: unable to create UTF-8 string.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_name_to_id_map_entry_get_utf8_string(
+ pypff_name_to_id_map_entry->name_to_id_map_entry,
+ (uint8_t *) utf8_string,
+ utf8_string_size,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve string name value.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ PyMem_Free(
+ utf8_string );
+
+ return( NULL );
+ }
+ string_object = PyUnicode_DecodeUTF8(
+ utf8_string,
+ (Py_ssize_t) utf8_string_size - 1,
+ NULL );
+
+ PyMem_Free(
+ utf8_string );
+
+ return( string_object );
+}
+
+/* Retrieves the property-set GUID
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_name_to_id_map_entry_get_guid(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
+{
+ PyObject *bytes_object = NULL;
+ libcerror_error_t *error = NULL;
+ static char *function = "pypff_name_to_id_map_entry_get_guid";
+ uint8_t guid[ 16 ];
+ int result = 0;
+
+ PYPFF_UNREFERENCED_PARAMETER( arguments )
+
+ if( ( pypff_name_to_id_map_entry == NULL )
+ || ( pypff_name_to_id_map_entry->name_to_id_map_entry == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid name to ID map entry.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_name_to_id_map_entry_get_guid(
+ pypff_name_to_id_map_entry->name_to_id_map_entry,
+ guid,
+ 16,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result != 1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve property-set GUID.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ bytes_object = PyBytes_FromStringAndSize(
+ (char *) guid,
+ 16 );
+
+ return( bytes_object );
+}
diff --git a/pypff/pypff_name_to_id_map_entry.h b/pypff/pypff_name_to_id_map_entry.h
new file mode 100644
index 00000000..4e380de5
--- /dev/null
+++ b/pypff/pypff_name_to_id_map_entry.h
@@ -0,0 +1,85 @@
+/*
+ * Python object wrapper of libpff_name_to_id_map_entry_t
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#if !defined( _PYPFF_NAME_TO_ID_MAP_ENTRY_H )
+#define _PYPFF_NAME_TO_ID_MAP_ENTRY_H
+
+#include
+#include
+
+#include "pypff_libpff.h"
+#include "pypff_python.h"
+
+#if defined( __cplusplus )
+extern "C" {
+#endif
+
+typedef struct pypff_name_to_id_map_entry pypff_name_to_id_map_entry_t;
+
+struct pypff_name_to_id_map_entry
+{
+ /* Python object initialization
+ */
+ PyObject_HEAD
+
+ /* The libpff name to ID map entry
+ */
+ libpff_name_to_id_map_entry_t *name_to_id_map_entry;
+
+ /* The parent object
+ */
+ PyObject *parent_object;
+};
+
+extern PyMethodDef pypff_name_to_id_map_entry_object_methods[];
+extern PyTypeObject pypff_name_to_id_map_entry_type_object;
+
+PyObject *pypff_name_to_id_map_entry_new(
+ libpff_name_to_id_map_entry_t *name_to_id_map_entry,
+ PyObject *parent_object );
+
+int pypff_name_to_id_map_entry_init(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry );
+
+void pypff_name_to_id_map_entry_free(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry );
+
+PyObject *pypff_name_to_id_map_entry_get_type(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments );
+
+PyObject *pypff_name_to_id_map_entry_get_number(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments );
+
+PyObject *pypff_name_to_id_map_entry_get_string(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments );
+
+PyObject *pypff_name_to_id_map_entry_get_guid(
+ pypff_name_to_id_map_entry_t *pypff_name_to_id_map_entry,
+ PyObject *arguments );
+
+#if defined( __cplusplus )
+}
+#endif
+
+#endif /* !defined( _PYPFF_NAME_TO_ID_MAP_ENTRY_H ) */
diff --git a/pypff/pypff_recipients.c b/pypff/pypff_recipients.c
index 1744594a..7759b41d 100644
--- a/pypff/pypff_recipients.c
+++ b/pypff/pypff_recipients.c
@@ -37,6 +37,19 @@
PyMethodDef pypff_recipients_object_methods[] = {
/* Functions to access the recipients values */
+ { "get_number_of_recipients",
+ (PyCFunction) pypff_item_get_number_of_record_sets,
+ METH_NOARGS,
+ "get_number_of_recipients() -> Integer or None\n"
+ "\n"
+ "Retrieves the number of recipients." },
+
+ { "get_recipient",
+ (PyCFunction) pypff_recipients_get_recipient,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_recipient(recipient_index) -> Object or None\n"
+ "\n"
+ "Retrieves the recipient specified by the index." },
/* Sentinel */
{ NULL, NULL, 0, NULL }
@@ -44,6 +57,18 @@ PyMethodDef pypff_recipients_object_methods[] = {
PyGetSetDef pypff_recipients_object_get_set_definitions[] = {
+ { "number_of_recipients",
+ (getter) pypff_item_get_number_of_record_sets,
+ (setter) 0,
+ "The number of recipients.",
+ NULL },
+
+ { "recipients",
+ (getter) pypff_item_get_record_sets,
+ (setter) 0,
+ "The recipients.",
+ NULL },
+
/* Sentinel */
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -143,3 +168,41 @@ PyTypeObject pypff_recipients_type_object = {
0
};
+/* Retrieves a specific recipient by index
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_recipients_get_recipient(
+ pypff_item_t *pypff_recipients,
+ PyObject *arguments,
+ PyObject *keywords )
+{
+ PyObject *recipient_object = NULL;
+ static char *function = "pypff_recipients_get_recipient";
+ static char *keyword_list[] = { "recipient_index", NULL };
+ int recipient_index = 0;
+
+ if( pypff_recipients == NULL )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid recipients.",
+ function );
+
+ return( NULL );
+ }
+ if( PyArg_ParseTupleAndKeywords(
+ arguments,
+ keywords,
+ "i",
+ keyword_list,
+ &recipient_index ) == 0 )
+ {
+ return( NULL );
+ }
+ recipient_object = pypff_item_get_record_set_by_index(
+ (PyObject *) pypff_recipients,
+ recipient_index );
+
+ return( recipient_object );
+}
+
diff --git a/pypff/pypff_recipients.h b/pypff/pypff_recipients.h
index ed906e04..44852a25 100644
--- a/pypff/pypff_recipients.h
+++ b/pypff/pypff_recipients.h
@@ -35,6 +35,11 @@ extern "C" {
extern PyMethodDef pypff_recipients_object_methods[];
extern PyTypeObject pypff_recipients_type_object;
+PyObject *pypff_recipients_get_recipient(
+ pypff_item_t *pypff_recipients,
+ PyObject *arguments,
+ PyObject *keywords );
+
#if defined( __cplusplus )
}
#endif
diff --git a/pypff/pypff_record_entry.c b/pypff/pypff_record_entry.c
index 6c2124ee..420c3dee 100644
--- a/pypff/pypff_record_entry.c
+++ b/pypff/pypff_record_entry.c
@@ -31,6 +31,8 @@
#include "pypff_integer.h"
#include "pypff_libcerror.h"
#include "pypff_libpff.h"
+#include "pypff_multi_value.h"
+#include "pypff_name_to_id_map_entry.h"
#include "pypff_python.h"
#include "pypff_record_entry.h"
#include "pypff_unused.h"
@@ -51,6 +53,20 @@ PyMethodDef pypff_record_entry_object_methods[] = {
"\n"
"Retrieves the value type." },
+ { "get_name_to_id_map_entry",
+ (PyCFunction) pypff_record_entry_get_name_to_id_map_entry,
+ METH_NOARGS,
+ "get_name_to_id_map_entry() -> Object or None\n"
+ "\n"
+ "Retrieves the name to ID map entry." },
+
+ { "get_multi_value",
+ (PyCFunction) pypff_record_entry_get_multi_value,
+ METH_NOARGS,
+ "get_multi_value() -> Object or None\n"
+ "\n"
+ "Retrieves the multi value." },
+
{ "get_data",
(PyCFunction) pypff_record_entry_get_data,
METH_NOARGS,
@@ -118,6 +134,18 @@ PyGetSetDef pypff_record_entry_object_get_set_definitions[] = {
"The value type.",
NULL },
+ { "name_to_id_map_entry",
+ (getter) pypff_record_entry_get_name_to_id_map_entry,
+ (setter) 0,
+ "The name to ID map entry.",
+ NULL },
+
+ { "multi_value",
+ (getter) pypff_record_entry_get_multi_value,
+ (setter) 0,
+ "The multi value.",
+ NULL },
+
{ "data",
(getter) pypff_record_entry_get_data,
(setter) 0,
@@ -538,6 +566,165 @@ PyObject *pypff_record_entry_get_value_type(
return( integer_object );
}
+/* Retrieves the name to ID map entry
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_record_entry_get_name_to_id_map_entry(
+ pypff_record_entry_t *pypff_record_entry,
+ PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
+{
+ PyObject *name_to_id_map_entry_object = NULL;
+ libcerror_error_t *error = NULL;
+ libpff_name_to_id_map_entry_t *name_to_id_map_entry = NULL;
+ static char *function = "pypff_record_entry_get_name_to_id_map_entry";
+ int result = 0;
+
+ PYPFF_UNREFERENCED_PARAMETER( arguments )
+
+ if( ( pypff_record_entry == NULL )
+ || ( pypff_record_entry->record_entry == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid record entry.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_record_entry_get_name_to_id_map_entry(
+ pypff_record_entry->record_entry,
+ &name_to_id_map_entry,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result == -1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve name to ID map entry.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( result == 0 )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ name_to_id_map_entry_object = pypff_name_to_id_map_entry_new(
+ name_to_id_map_entry,
+ (PyObject *) pypff_record_entry );
+
+ return( name_to_id_map_entry_object );
+}
+
+/* Retrieves the multi value
+ * Returns a Python object if successful or NULL on error
+ */
+PyObject *pypff_record_entry_get_multi_value(
+ pypff_record_entry_t *pypff_record_entry,
+ PyObject *arguments PYPFF_ATTRIBUTE_UNUSED )
+{
+ PyObject *multi_value_object = NULL;
+ libcerror_error_t *error = NULL;
+ libpff_multi_value_t *multi_value = NULL;
+ static char *function = "pypff_record_entry_get_multi_value";
+ uint32_t value_type = 0;
+ int result = 0;
+
+ PYPFF_UNREFERENCED_PARAMETER( arguments )
+
+ if( ( pypff_record_entry == NULL )
+ || ( pypff_record_entry->record_entry == NULL ) )
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: invalid record entry.",
+ function );
+
+ return( NULL );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_record_entry_get_value_type(
+ pypff_record_entry->record_entry,
+ &value_type,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result == -1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve value type.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( ( result == 0 )
+ || ( ( value_type & LIBPFF_VALUE_TYPE_MULTI_VALUE_FLAG ) == 0 ) )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ Py_BEGIN_ALLOW_THREADS
+
+ result = libpff_record_entry_get_multi_value(
+ pypff_record_entry->record_entry,
+ &multi_value,
+ &error );
+
+ Py_END_ALLOW_THREADS
+
+ if( result == -1 )
+ {
+ pypff_error_raise(
+ error,
+ PyExc_IOError,
+ "%s: unable to retrieve multi value.",
+ function );
+
+ libcerror_error_free(
+ &error );
+
+ return( NULL );
+ }
+ if( result == 0 )
+ {
+ Py_IncRef(
+ Py_None );
+
+ return( Py_None );
+ }
+ multi_value_object = pypff_multi_value_new(
+ multi_value,
+ (PyObject *) pypff_record_entry );
+
+ if( multi_value_object == NULL )
+ {
+ libpff_multi_value_free(
+ &multi_value,
+ NULL );
+ }
+ return( multi_value_object );
+}
+
/* Retrieves the data
* Returns a Python object if successful or NULL on error
*/
diff --git a/pypff/pypff_record_entry.h b/pypff/pypff_record_entry.h
index 4983e504..440cf308 100644
--- a/pypff/pypff_record_entry.h
+++ b/pypff/pypff_record_entry.h
@@ -71,6 +71,14 @@ PyObject *pypff_record_entry_get_value_type(
pypff_record_entry_t *pypff_record_entry,
PyObject *arguments );
+PyObject *pypff_record_entry_get_name_to_id_map_entry(
+ pypff_record_entry_t *pypff_record_entry,
+ PyObject *arguments );
+
+PyObject *pypff_record_entry_get_multi_value(
+ pypff_record_entry_t *pypff_record_entry,
+ PyObject *arguments );
+
PyObject *pypff_record_entry_get_data(
pypff_record_entry_t *pypff_record_entry,
PyObject *arguments );
diff --git a/pypff/pypff_task.c b/pypff/pypff_task.c
new file mode 100644
index 00000000..b3005557
--- /dev/null
+++ b/pypff/pypff_task.c
@@ -0,0 +1,134 @@
+/*
+ * Python object wrapper of libpff task items
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include "pypff_message.h"
+#include "pypff_python.h"
+#include "pypff_task.h"
+
+PyMethodDef pypff_task_object_methods[] = {
+
+ /* Sentinel */
+ { NULL, NULL, 0, NULL }
+};
+
+PyGetSetDef pypff_task_object_get_set_definitions[] = {
+
+ /* Sentinel */
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+PyTypeObject pypff_task_type_object = {
+ PyVarObject_HEAD_INIT( NULL, 0 )
+
+ /* tp_name */
+ "pypff.task",
+ /* tp_basicsize */
+ sizeof( pypff_item_t ),
+ /* tp_itemsize */
+ 0,
+ /* tp_dealloc */
+ 0,
+ /* tp_print */
+ 0,
+ /* tp_getattr */
+ 0,
+ /* tp_setattr */
+ 0,
+ /* tp_compare */
+ 0,
+ /* tp_repr */
+ 0,
+ /* tp_as_number */
+ 0,
+ /* tp_as_sequence */
+ 0,
+ /* tp_as_mapping */
+ 0,
+ /* tp_hash */
+ 0,
+ /* tp_call */
+ 0,
+ /* tp_str */
+ 0,
+ /* tp_getattro */
+ 0,
+ /* tp_setattro */
+ 0,
+ /* tp_as_buffer */
+ 0,
+ /* tp_flags */
+ Py_TPFLAGS_DEFAULT,
+ /* tp_doc */
+ "pypff task object (wraps task type libpff_item_t)",
+ /* tp_traverse */
+ 0,
+ /* tp_clear */
+ 0,
+ /* tp_richcompare */
+ 0,
+ /* tp_weaklistoffset */
+ 0,
+ /* tp_iter */
+ 0,
+ /* tp_iternext */
+ 0,
+ /* tp_methods */
+ pypff_task_object_methods,
+ /* tp_members */
+ 0,
+ /* tp_getset */
+ pypff_task_object_get_set_definitions,
+ /* tp_base */
+ &pypff_message_type_object,
+ /* tp_dict */
+ 0,
+ /* tp_descr_get */
+ 0,
+ /* tp_descr_set */
+ 0,
+ /* tp_dictoffset */
+ 0,
+ /* tp_init */
+ 0,
+ /* tp_alloc */
+ 0,
+ /* tp_new */
+ 0,
+ /* tp_free */
+ 0,
+ /* tp_is_gc */
+ 0,
+ /* tp_bases */
+ NULL,
+ /* tp_mro */
+ NULL,
+ /* tp_cache */
+ NULL,
+ /* tp_subclasses */
+ NULL,
+ /* tp_weaklist */
+ NULL,
+ /* tp_del */
+ 0
+};
diff --git a/pypff/pypff_task.h b/pypff/pypff_task.h
new file mode 100644
index 00000000..87cd3fe9
--- /dev/null
+++ b/pypff/pypff_task.h
@@ -0,0 +1,42 @@
+/*
+ * Python object wrapper of libpff task items
+ *
+ * Copyright (C) 2008-2026, Joachim Metz
+ *
+ * Refer to AUTHORS for acknowledgements.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+#if !defined( _PYPFF_TASK_H )
+#define _PYPFF_TASK_H
+
+#include
+#include
+
+#include "pypff_message.h"
+#include "pypff_python.h"
+
+#if defined( __cplusplus )
+extern "C" {
+#endif
+
+extern PyMethodDef pypff_task_object_methods[];
+extern PyTypeObject pypff_task_type_object;
+
+#if defined( __cplusplus )
+}
+#endif
+
+#endif /* !defined( _PYPFF_TASK_H ) */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 460483ad..633d7862 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -36,6 +36,7 @@ endif
check_SCRIPTS = \
pypff_test_file.py \
+ pypff_test_module.py \
pypff_test_support.py
check_PROGRAMS = \
diff --git a/tests/pypff_test_file.py b/tests/pypff_test_file.py
index bd5e781c..e8684723 100644
--- a/tests/pypff_test_file.py
+++ b/tests/pypff_test_file.py
@@ -267,9 +267,15 @@ def test_get_message_store(self):
pff_file.open(test_source)
- _ = pff_file.get_message_store()
+ message_store = pff_file.get_message_store()
- _ = pff_file.message_store
+ if message_store:
+ self.assertIsInstance(message_store, pypff.message_store)
+
+ message_store = pff_file.message_store
+
+ if message_store:
+ self.assertIsInstance(message_store, pypff.message_store)
pff_file.close()
diff --git a/tests/pypff_test_message.py b/tests/pypff_test_message.py
index cfeccd02..68afbe4f 100644
--- a/tests/pypff_test_message.py
+++ b/tests/pypff_test_message.py
@@ -400,7 +400,16 @@ def test_get_recipients(self):
if not message_item:
raise unittest.SkipTest("missing message item")
- _ = message_item.recipients
+ recipients = message_item.recipients
+
+ if recipients:
+ self.assertIsInstance(recipients, pypff.recipients)
+ number_of_recipients = recipients.get_number_of_recipients()
+ self.assertEqual(number_of_recipients, recipients.number_of_recipients)
+
+ if number_of_recipients:
+ self.assertIsNotNone(recipients.get_recipient(0))
+ self.assertEqual(len(recipients.recipients), number_of_recipients)
finally:
pff_file.close()
diff --git a/tests/pypff_test_module.py b/tests/pypff_test_module.py
new file mode 100644
index 00000000..5b9a12dc
--- /dev/null
+++ b/tests/pypff_test_module.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+#
+# Python-bindings module type test script
+#
+# Copyright (C) 2008-2026, Joachim Metz
+#
+# Refer to AUTHORS for acknowledgements.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+
+import unittest
+
+import pypff
+
+
+class ModuleTypeTests(unittest.TestCase):
+ """Tests the Python types exposed by the module."""
+
+ def test_specialized_types(self):
+ """Tests the specialized item and record-entry value types."""
+ self.assertTrue(issubclass(pypff.message_store, pypff.item))
+ self.assertTrue(issubclass(pypff.task, pypff.message))
+ self.assertTrue(issubclass(pypff.recipients, pypff.item))
+ self.assertIsInstance(pypff.multi_value, type)
+ self.assertIsInstance(pypff.name_to_id_map_entry, type)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/tests/pypff_test_record_entry.py b/tests/pypff_test_record_entry.py
index b835141e..607a99c6 100644
--- a/tests/pypff_test_record_entry.py
+++ b/tests/pypff_test_record_entry.py
@@ -30,6 +30,17 @@
class RecordEntryTypeTests(unittest.TestCase):
"""Tests the record_entry type."""
+ def _get_record_entries(self, item):
+ """Yields record entries from an item tree."""
+ if not item:
+ return
+
+ for record_set in item.record_sets:
+ yield from record_set.entries
+
+ for sub_item in item.sub_items:
+ yield from self._get_record_entries(sub_item)
+
def test_get_entry_type(self):
"""Tests the get_entry_type function and entry_type property."""
test_source = getattr(unittest, "source", None)
@@ -140,6 +151,75 @@ def test_get_data(self):
finally:
pff_file.close()
+ def test_get_name_to_id_map_entry(self):
+ """Tests the name_to_id_map_entry property."""
+ test_source = getattr(unittest, "source", None)
+ if not test_source:
+ raise unittest.SkipTest("missing source")
+
+ pff_file = pypff.file()
+
+ pff_file.open(test_source)
+
+ try:
+ map_entry = None
+
+ for record_entry in self._get_record_entries(pff_file.root_folder):
+ map_entry = record_entry.get_name_to_id_map_entry()
+ if map_entry:
+ break
+
+ if not map_entry:
+ raise unittest.SkipTest("missing name to ID map entry")
+
+ self.assertIsInstance(map_entry, pypff.name_to_id_map_entry)
+ self.assertEqual(map_entry.get_type(), map_entry.type)
+ self.assertEqual(map_entry.get_guid(), map_entry.guid)
+ self.assertEqual(len(map_entry.guid), 16)
+
+ number = map_entry.get_number()
+ string = map_entry.get_string()
+ self.assertTrue(number is not None or string is not None)
+ self.assertEqual(number, map_entry.number)
+ self.assertEqual(string, map_entry.string)
+
+ finally:
+ pff_file.close()
+
+ def test_get_multi_value(self):
+ """Tests the multi_value property."""
+ test_source = getattr(unittest, "source", None)
+ if not test_source:
+ raise unittest.SkipTest("missing source")
+
+ pff_file = pypff.file()
+
+ pff_file.open(test_source)
+
+ try:
+ multi_value = None
+
+ for record_entry in self._get_record_entries(pff_file.root_folder):
+ multi_value = record_entry.get_multi_value()
+ if multi_value:
+ break
+
+ if not multi_value:
+ raise unittest.SkipTest("missing multi value")
+
+ self.assertIsInstance(multi_value, pypff.multi_value)
+ self.assertEqual(
+ multi_value.get_number_of_values(), multi_value.number_of_values
+ )
+
+ if multi_value.number_of_values:
+ self.assertIsInstance(multi_value.get_value_type(0), int)
+ value = multi_value.get_value(0)
+ self.assertTrue(value is None or isinstance(value, bytes))
+
+ finally:
+ pff_file.close()
+
# TODO: add tests for data_as_boolean
# TODO: add tests for data_as_integer
# TODO: add tests for data_as_datetime