diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2023-05-24 00:38:15 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2023-05-24 00:38:15 (GMT) |
commit | 5eab5f1bf3665e948e2054817fb688963dc86935 (patch) | |
tree | 0d0547b7fd90cf51992a449bdca0d9f7b38b3174 /plugins/kaitai/python | |
parent | 9f4abb8a20871c64b33f88ad5538bbbe111c1d4c (diff) |
Define a first implementation of Kaitai parsing.
Diffstat (limited to 'plugins/kaitai/python')
41 files changed, 6843 insertions, 0 deletions
diff --git a/plugins/kaitai/python/Makefile.am b/plugins/kaitai/python/Makefile.am new file mode 100644 index 0000000..ab40744 --- /dev/null +++ b/plugins/kaitai/python/Makefile.am @@ -0,0 +1,25 @@ + +noinst_LTLIBRARIES = libkaitaipython.la + +libkaitaipython_la_SOURCES = \ + array.h array.c \ + module.h module.c \ + parser.h parser.c \ + record.h record.c \ + scope.h scope.c \ + stream.h stream.c + +libkaitaipython_la_LIBADD = \ + parsers/libkaitaipythonparsers.la \ + records/libkaitaipythonrecords.la + +libkaitaipython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaipython_la_SOURCES:%c=) + + +SUBDIRS = parsers records diff --git a/plugins/kaitai/python/array.c b/plugins/kaitai/python/array.c new file mode 100644 index 0000000..4973c76 --- /dev/null +++ b/plugins/kaitai/python/array.c @@ -0,0 +1,265 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * array.h - équivalent Python du fichier "plugins/kaitai/array.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "array.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../array-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_array, G_TYPE_KAITAI_ARRAY); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_array_init(PyObject *, PyObject *, PyObject *); + +/* Convertit un tableau Kaitai en série d'octets si possible. */ +static PyObject *py_kaitai_array___bytes__(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_array_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define KAITAI_ARRAY_DOC \ + "KaitaiArray defines an array for collecting various Kaitai items." \ + "\n" \ + "Instances can be created using following constructor:\n" \ + "\n" \ + " KaitaiArray()" \ + "\n" \ + "In this implementation, arrays do not have to carry items all" \ + " belonging to the same type. Access and conversions to bytes are" \ + " handled and checked at runtime." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un binaire. * +* args = arguments fournis à l'appel. * +* * +* Description : Convertit un tableau Kaitai en série d'octets si possible. * +* * +* Retour : Série d'octets ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_array___bytes__(PyObject *self, PyObject *args) +{ + PyObject *result; /* Représentation à renvoyer */ + GKaitaiArray *array; /* Tableau à manipuler */ + sized_string_t bytes; /* Version en série d'octets */ + bool status; /* Bilan de la conversion */ + +#define KAITAI_ARRAY_AS_BYTES_METHOD PYTHON_METHOD_DEF \ +( \ + __bytes__, "$self, /", \ + METH_NOARGS, py_kaitai_array, \ + "Provide a bytes representation of the array, when possible" \ + " and without implementing the Python buffer protocol.\n" \ + "\n" \ + "THe result is bytes or a *TypeError* exception is raised if" \ + " the array is not suitable for a conversion to bytes." \ +) + + array = G_KAITAI_ARRAY(pygobject_get(self)); + + status = g_kaitai_array_convert_to_bytes(array, &bytes); + + if (status) + { + result = PyBytes_FromStringAndSize(bytes.data, bytes.len); + exit_szstr(&bytes); + } + else + { + PyErr_SetString(PyExc_TypeError, "unable to convert the Kaitai array to bytes"); + result = NULL; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_array_type(void) +{ + static PyMethodDef py_kaitai_array_methods[] = { + KAITAI_ARRAY_AS_BYTES_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_array_getseters[] = { + { NULL } + }; + + static PyTypeObject py_kaitai_array_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiArray", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_ARRAY_DOC, + + .tp_methods = py_kaitai_array_methods, + .tp_getset = py_kaitai_array_getseters, + + .tp_init = py_kaitai_array_init, + .tp_new = py_kaitai_array_new, + + }; + + return &py_kaitai_array_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiArray. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_array_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiArray' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_array_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ARRAY, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en tableau d'éléments Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_array(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_array_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai array"); + break; + + case 1: + *((GKaitaiArray **)dst) = G_KAITAI_ARRAY(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/array.h b/plugins/kaitai/python/array.h new file mode 100644 index 0000000..aeba541 --- /dev/null +++ b/plugins/kaitai/python/array.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * array.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/array.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_ARRAY_H +#define _PLUGINS_KAITAI_PYTHON_ARRAY_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_array_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiArray'. */ +bool ensure_python_kaitai_array_is_registered(void); + +/* Tente de convertir en tableau d'éléments Kaitai. */ +int convert_to_kaitai_array(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_ARRAY_H */ diff --git a/plugins/kaitai/python/module.c b/plugins/kaitai/python/module.c new file mode 100644 index 0000000..fa1f9c2 --- /dev/null +++ b/plugins/kaitai/python/module.c @@ -0,0 +1,132 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire kaitai en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "array.h" +#include "parser.h" +#include "record.h" +#include "scope.h" +#include "stream.h" +#include "parsers/module.h" +#include "records/module.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.kaitai' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_module_to_python_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_KAITAI_DOC \ + "kaitai is a module trying to reverse some of the effects produced by ProGuard.\n" \ + "\n" \ + "Its action is focused on reverting name obfuscation by running binary diffing against" \ + " OpenSource packages from the AOSP." + + static PyModuleDef py_chrysalide_kaitai_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.kaitai", + .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins"); + + module = build_python_module(super, &py_chrysalide_kaitai_module); + + result = (module != NULL); + + assert(result); + + if (result) result = add_kaitai_parsers_module(); + if (result) result = add_kaitai_records_module(); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.kaitai'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_kaitai_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_kaitai_array_is_registered(); + if (result) result = ensure_python_kaitai_parser_is_registered(); + if (result) result = ensure_python_match_record_is_registered(); + if (result) result = ensure_python_kaitai_scope_is_registered(); + if (result) result = ensure_python_kaitai_stream_is_registered(); + + if (result) result = populate_kaitai_parsers_module(); + if (result) result = populate_kaitai_records_module(); + + assert(result); + + return result; + +} diff --git a/plugins/kaitai/python/module.h b/plugins/kaitai/python/module.h new file mode 100644 index 0000000..939de07 --- /dev/null +++ b/plugins/kaitai/python/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire kaitai en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_MODULE_H +#define _PLUGINS_KAITAI_PYTHON_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.kaitai' au module Python. */ +bool add_kaitai_module_to_python_module(void); + +/* Intègre les objets du module 'plugins.kaitai'. */ +bool populate_kaitai_module(void); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_MODULE_H */ diff --git a/plugins/kaitai/python/parser.c b/plugins/kaitai/python/parser.c new file mode 100644 index 0000000..067d3b0 --- /dev/null +++ b/plugins/kaitai/python/parser.c @@ -0,0 +1,205 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.h - équivalent Python du fichier "plugins/kaitai/parser.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "parser.h" + + +#include <pygobject.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../parser.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(kaitai_parser, G_TYPE_KAITAI_PARSER, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_parser_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_parser_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define KAITAI_PARSER_DOC \ + "KaitaiParser is the class providing support for parsing binary contents" \ + " using a special declarative language." \ + "\n" \ + "It is the Python bindings for a C implementation of the specifications" \ + " described at http://kaitai.io/." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_parser_type(void) +{ + static PyMethodDef py_kaitai_parser_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_parser_getseters[] = { + { NULL } + }; + + static PyTypeObject py_kaitai_parser_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiParser", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_PARSER_DOC, + + .tp_methods = py_kaitai_parser_methods, + .tp_getset = py_kaitai_parser_getseters, + + .tp_init = py_kaitai_parser_init, + .tp_new = py_kaitai_parser_new, + + }; + + return &py_kaitai_parser_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiParser.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_parser_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiParser' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_parser_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_PARSER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en lecteur de données Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_parser(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_parser_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai parser"); + break; + + case 1: + *((GKaitaiParser **)dst) = G_KAITAI_PARSER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parser.h b/plugins/kaitai/python/parser.h new file mode 100644 index 0000000..f4b6c96 --- /dev/null +++ b/plugins/kaitai/python/parser.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parser.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSER_H +#define _PLUGINS_KAITAI_PYTHON_PARSER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_parser_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiParser'. */ +bool ensure_python_kaitai_parser_is_registered(void); + +/* Tente de convertir en lecteur de données Kaitai. */ +int convert_to_kaitai_parser(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSER_H */ diff --git a/plugins/kaitai/python/parsers/Makefile.am b/plugins/kaitai/python/parsers/Makefile.am new file mode 100644 index 0000000..4c418af --- /dev/null +++ b/plugins/kaitai/python/parsers/Makefile.am @@ -0,0 +1,19 @@ + +noinst_LTLIBRARIES = libkaitaipythonparsers.la + +libkaitaipythonparsers_la_SOURCES = \ + attribute.h attribute.c \ + enum.h enum.c \ + instance.h instance.c \ + meta.h meta.c \ + module.h module.c \ + struct.h struct.c \ + type.h type.c + +libkaitaipythonparsers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaipythonparsers_la_SOURCES:%c=) diff --git a/plugins/kaitai/python/parsers/attribute.c b/plugins/kaitai/python/parsers/attribute.c new file mode 100644 index 0000000..c8ea314 --- /dev/null +++ b/plugins/kaitai/python/parsers/attribute.c @@ -0,0 +1,420 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * attribute.h - équivalent Python du fichier "plugins/kaitai/parsers/attribute.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "attribute.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "../parser.h" +#include "../../parsers/attribute-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_attribute, G_TYPE_KAITAI_ATTRIBUTE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_attribute_init(PyObject *, PyObject *, PyObject *); + +/* Indique la désignation brute d'un identifiant Kaitai. */ +static PyObject *py_kaitai_attribute_get_raw_id(PyObject *, void *); + +/* Indique la désignation originelle d'un identifiant Kaitai. */ +static PyObject *py_kaitai_attribute_get_original_id(PyObject *, void *); + +/* Fournit une éventuelle documentation concernant l'attribut. */ +static PyObject *py_kaitai_attribute_get_doc(PyObject *, void *); + +/* Détermine si l'attribue porte une valeur entière signée. */ +static PyObject *py_kaitai_attribute_get_handle_signed_integer(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_attribute_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiAttribute *attrib; /* Création GLib à transmettre */ + +#define KAITAI_ATTRIBUTE_DOC \ + "KaitaiAttribute is the class providing support for parsing binary" \ + " contents using a special declarative language." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiAttribute(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the Attribute" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + if (!g_kaitai_attribute_create(attrib, parent, true)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai attribute.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique la désignation brute d'un identifiant Kaitai. * +* * +* Retour : Valeur brute de l'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_raw_id(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + const char *value; /* Valeur à transmettre */ + +#define KAITAI_ATTRIBUTE_RAW_ID_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + raw_id, py_kaitai_attribute, \ + "Raw value used by Kaitai to identify one attribute" \ + " among others.\n" \ + "\n" \ + "The returned indentifier is a string value." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + value = g_kaitai_attribute_get_raw_id(attrib); + assert(value != NULL); + + result = PyUnicode_FromString(value); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique la désignation originelle d'un identifiant Kaitai. * +* * +* Retour : Valeur originelle de l'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_original_id(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + const char *value; /* Valeur à transmettre */ + +#define KAITAI_ATTRIBUTE_ORIGINAL_ID_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + original_id, py_kaitai_attribute, \ + "Optional alternative identifier for the attribute, as seen in" \ + " the original specifications.\n" \ + "\n" \ + "The returned value is a string or *None*." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + value = g_kaitai_attribute_get_original_id(attrib); + + if (value == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + result = PyUnicode_FromString(value); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit une éventuelle documentation concernant l'attribut. * +* * +* Retour : Description enregistrée ou None si absente. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_doc(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + const char *doc; /* Documentation à transmettre */ + +#define KAITAI_ATTRIBUTE_DOC_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + doc, py_kaitai_attribute, \ + "Optional documentation for the attribute.\n" \ + "\n" \ + "The returned value is a string or *None*." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + doc = g_kaitai_attribute_get_doc(attrib); + + if (doc == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + result = PyUnicode_FromString(doc); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Détermine si l'attribue porte une valeur entière signée. * +* * +* Retour : Bilan de la consultation : True si un entier signé est visé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_handle_signed_integer(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + bool status; /* Bilan d'une consultation */ + +#define KAITAI_ATTRIBUTE_HANDLE_SIGNED_INTEGER_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + handle_signed_integer, py_kaitai_attribute, \ + "Sign of the carried integer value, if any: positive or negative?\n" \ + "\n" \ + "This status is provided as a boolean value." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + status = g_kaitai_attribute_handle_signed_integer(attrib); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_attribute_type(void) +{ + static PyMethodDef py_kaitai_attribute_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_attribute_getseters[] = { + KAITAI_ATTRIBUTE_RAW_ID_ATTRIB, + KAITAI_ATTRIBUTE_ORIGINAL_ID_ATTRIB, + KAITAI_ATTRIBUTE_DOC_ATTRIB, + KAITAI_ATTRIBUTE_HANDLE_SIGNED_INTEGER_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_attribute_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiAttribute", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_ATTRIBUTE_DOC, + + .tp_methods = py_kaitai_attribute_methods, + .tp_getset = py_kaitai_attribute_getseters, + + .tp_init = py_kaitai_attribute_init, + .tp_new = py_kaitai_attribute_new, + + }; + + return &py_kaitai_attribute_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....KaitaiAttribute. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_attribute_is_registered(void) +{ + PyTypeObject *type; /* Type 'KaitaiAttribute' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_attribute_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_parser_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ATTRIBUTE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en attribut de données Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_attribute(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_attribute_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai attribute"); + break; + + case 1: + *((GKaitaiAttribute **)dst) = G_KAITAI_ATTRIBUTE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/attribute.h b/plugins/kaitai/python/parsers/attribute.h new file mode 100644 index 0000000..931e769 --- /dev/null +++ b/plugins/kaitai/python/parsers/attribute.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * attribute.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/attribute.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_attribute_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiAttribute'. */ +bool ensure_python_kaitai_attribute_is_registered(void); + +/* Tente de convertir en attribut de données Kaitai. */ +int convert_to_kaitai_attribute(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H */ diff --git a/plugins/kaitai/python/parsers/enum.c b/plugins/kaitai/python/parsers/enum.c new file mode 100644 index 0000000..9200c6f --- /dev/null +++ b/plugins/kaitai/python/parsers/enum.c @@ -0,0 +1,468 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enum.h - équivalent Python du fichier "plugins/kaitai/parsers/enum.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "enum.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "../../parsers/enum-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_enum, G_TYPE_KAITAI_ENUM); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_enum_init(PyObject *, PyObject *, PyObject *); + +/* Traduit une étiquette brute en constante d'énumération. */ +static PyObject *py_kaitai_enum_find_value(PyObject *, PyObject *); + +/* Traduit une constante d'énumération en étiquette brute. */ +static PyObject *py_kaitai_enum_find_label(PyObject *, PyObject *); + +/* Traduit une constante d'énumération en documentation. */ +static PyObject *py_kaitai_enum_find_documentation(PyObject *, PyObject *); + +/* Fournit le nom principal d'une énumération. */ +static PyObject *py_kaitai_enum_get_name(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_enum_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Création GLib à transmettre */ + +#define KAITAI_ENUM_DOC \ + "The KaitaiEnum class maps integer constants to symbolic names using" \ + " Kaitai definitions.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiEnum(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the EnumSpec" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + if (!g_kaitai_enum_create(kenum, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai enumeration.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'énumération Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Traduit une étiquette brute en constante d'énumération. * +* * +* Retour : Valeur retrouvée ou None en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_find_value(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + const char *label; /* Etiquette à rechercher */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Enumération Kaitai courante */ + sized_string_t cstr; /* CHaîne avec sa longueur */ + bool status; /* Bilan de la conversion */ + resolved_value_t value; /* valeur à transformer */ + +#define KAITAI_ENUM_FIND_VALUE_METHOD PYTHON_METHOD_DEF \ +( \ + find_value, "$self, label", \ + METH_VARARGS, py_kaitai_enum, \ + "Translate a given enumeration label into its relative value.\n" \ + "\n" \ + "The *label* argument is expected to be a string.\n" \ + "\n" \ + "The result is an integer or *None* in case of resolution failure." \ +) + + ret = PyArg_ParseTuple(args, "s", &label); + if (!ret) return NULL; + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + cstr.data = (char *)label; + cstr.len = strlen(label); + + status = g_kaitai_enum_find_value(kenum, &cstr, &value); + + if (status) + { + if (value.type == GVT_UNSIGNED_INTEGER) + result = PyLong_FromUnsignedLongLong(value.unsigned_integer); + else + { + assert(value.type == GVT_SIGNED_INTEGER); + result = PyLong_FromLongLong(value.signed_integer); + } + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'énumération Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Traduit une constante d'énumération en étiquette brute. * +* * +* Retour : Désignation ou None en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_find_label(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + int prefix; /* Préfixe attendu ? */ + resolved_value_t value; /* valeur à transformer */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Enumération Kaitai courante */ + char *label; /* Etiquette reconstruite */ + +#define KAITAI_ENUM_FIND_LABEL_METHOD PYTHON_METHOD_DEF \ +( \ + find_label, "$self, value, / , prefix=False", \ + METH_VARARGS, py_kaitai_enum, \ + "Provide the label linked to a constant value within the current" \ + " enumeration.\n" \ + "\n" \ + "The *value* is a simple integer, and *prefix* is a boolean indicating" \ + " if the result has to integrate the enumeration name as a prefix.\n" \ + "\n" \ + "The result is a string or *None* in case of resolution failure." \ +) + + prefix = 0; + + ret = PyArg_ParseTuple(args, "K|p", &value.unsigned_integer, prefix); + if (!ret) return NULL; + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + value.type = GVT_UNSIGNED_INTEGER; + label = g_kaitai_enum_find_label(kenum, &value, prefix); + + if (label != NULL) + { + result = PyUnicode_FromString(label); + free(label); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'énumération Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Traduit une constante d'énumération en documentation. * +* * +* Retour : Documentation associée à la valeur indiquée ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_find_documentation(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + resolved_value_t value; /* valeur à transformer */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Enumération Kaitai courante */ + char *doc; /* Documentation obtenue */ + +#define KAITAI_ENUM_FIND_DOCUMENTATION_METHOD PYTHON_METHOD_DEF \ +( \ + find_documentation, "$self, value", \ + METH_VARARGS, py_kaitai_enum, \ + "Provide the optional documentation linked to a constant value within" \ + " the current enumeration.\n" \ + "\n" \ + "The *value* is a simple integer.\n" \ + "\n" \ + "The result is a string or *None* if no documentation is registered" \ + " for the provided value." \ +) + + ret = PyArg_ParseTuple(args, "K", &value.unsigned_integer); + if (!ret) return NULL; + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + value.type = GVT_UNSIGNED_INTEGER; + doc = g_kaitai_enum_find_documentation(kenum, &value); + + if (doc != NULL) + { + result = PyUnicode_FromString(doc); + free(doc); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit le nom principal d'une énumération. * +* * +* Retour : Désignation de l'énumération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiEnum *kenum; /* Version native de l'objet */ + const char *name; /* Valeur à transmettre */ + +#define KAITAI_ENUM_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_kaitai_enum, \ + "Name of the enumeration group, as a string value." \ +) + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + name = g_kaitai_enum_get_name(kenum); + + result = PyUnicode_FromString(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_enum_type(void) +{ + static PyMethodDef py_kaitai_enum_methods[] = { + KAITAI_ENUM_FIND_VALUE_METHOD, + KAITAI_ENUM_FIND_LABEL_METHOD, + KAITAI_ENUM_FIND_DOCUMENTATION_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_enum_getseters[] = { + KAITAI_ENUM_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_enum_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiEnum", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_ENUM_DOC, + + .tp_methods = py_kaitai_enum_methods, + .tp_getset = py_kaitai_enum_getseters, + + .tp_init = py_kaitai_enum_init, + .tp_new = py_kaitai_enum_new + + }; + + return &py_kaitai_enum_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiEnum. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_enum_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiEnum' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_enum_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ENUM, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en ensemble d'énumérations Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_enum(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_enum_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai enumeration"); + break; + + case 1: + *((GKaitaiEnum **)dst) = G_KAITAI_ENUM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/enum.h b/plugins/kaitai/python/parsers/enum.h new file mode 100644 index 0000000..7172e69 --- /dev/null +++ b/plugins/kaitai/python/parsers/enum.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enum.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/enum.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_enum_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiEnum'. */ +bool ensure_python_kaitai_enum_is_registered(void); + +/* Tente de convertir en ensemble d'énumérations Kaitai. */ +int convert_to_kaitai_enum(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H */ diff --git a/plugins/kaitai/python/parsers/instance.c b/plugins/kaitai/python/parsers/instance.c new file mode 100644 index 0000000..d55b58c --- /dev/null +++ b/plugins/kaitai/python/parsers/instance.c @@ -0,0 +1,280 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instance.h - équivalent Python du fichier "plugins/kaitai/parsers/instance.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "instance.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "attribute.h" +#include "../../parsers/instance-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_instance, G_TYPE_KAITAI_INSTANCE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_instance_init(PyObject *, PyObject *, PyObject *); + +/* Indique le nom attribué à une instance Kaitai. */ +static PyObject *py_kaitai_instance_get_name(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_instance_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiInstance *attrib; /* Création GLib à transmettre */ + +#define KAITAI_INSTANCE_DOC \ + "KaitaiInstance is the class providing support for Kaitai computed" \ + " values.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiInstance(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the Instance" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + attrib = G_KAITAI_INSTANCE(pygobject_get(self)); + + if (!g_kaitai_instance_create(attrib, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai instance.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le nom attribué à une instance Kaitai. * +* * +* Retour : Désignation pointant l'instance. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_instance_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiInstance *inst; /* Version native de l'instance*/ + const char *name; /* Désignation à transmettre */ + +#define KAITAI_INSTANCE_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_kaitai_instance, \ + "Name used by Kaitai to identify the instance" \ + " among others.\n" \ + "\n" \ + "The returned indentifier is a string value." \ +) + + inst = G_KAITAI_INSTANCE(pygobject_get(self)); + + name = g_kaitai_instance_get_name(inst); + assert(name != NULL); + + result = PyUnicode_FromString(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_instance_type(void) +{ + static PyMethodDef py_kaitai_instance_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_instance_getseters[] = { + KAITAI_INSTANCE_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_instance_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiInstance", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_INSTANCE_DOC, + + .tp_methods = py_kaitai_instance_methods, + .tp_getset = py_kaitai_instance_getseters, + + .tp_init = py_kaitai_instance_init, + .tp_new = py_kaitai_instance_new, + + }; + + return &py_kaitai_instance_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....KaitaiInstance. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_instance_is_registered(void) +{ + PyTypeObject *type; /* Type 'KaitaiInstance' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_instance_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_attribute_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_INSTANCE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en instance Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_instance(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_instance_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai instance"); + break; + + case 1: + *((GKaitaiInstance **)dst) = G_KAITAI_INSTANCE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/instance.h b/plugins/kaitai/python/parsers/instance.h new file mode 100644 index 0000000..8a0a6cf --- /dev/null +++ b/plugins/kaitai/python/parsers/instance.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instance.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/instance.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_instance_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiInstance'. */ +bool ensure_python_kaitai_instance_is_registered(void); + +/* Tente de convertir en instance Kaitai. */ +int convert_to_kaitai_instance(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H */ diff --git a/plugins/kaitai/python/parsers/meta.c b/plugins/kaitai/python/parsers/meta.c new file mode 100644 index 0000000..3432640 --- /dev/null +++ b/plugins/kaitai/python/parsers/meta.c @@ -0,0 +1,366 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * meta.h - équivalent Python du fichier "plugins/kaitai/parsers/meta.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "meta.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/yaml/python/node.h> + + +#include "../../parsers/meta-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_meta, G_TYPE_KAITAI_META); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_meta_init(PyObject *, PyObject *, PyObject *); + +/* Fournit l'identifié associé à une définiton Kaitai. */ +static PyObject *py_kaitai_meta_get_id(PyObject *, void *); + +/* Fournit la désignation humaine d'une définiton Kaitai. */ +static PyObject *py_kaitai_meta_get_title(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_meta_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiMeta *kmeta; /* Création GLib à transmettre */ + +#define KAITAI_META_DOC \ + "The KaitaiMeta class stores general information about a Kaitai definition,"\ + " such as required imports or the default endianness for reading values.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiMeta(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the MetaSpec" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + kmeta = G_KAITAI_META(pygobject_get(self)); + + if (!g_kaitai_meta_create(kmeta, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai global description.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit l'identifié associé à une définiton Kaitai. * +* * +* Retour : Identifiant de définition complète ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_meta_get_id(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiMeta *meta; /* Version native de l'objet */ + const char *id; /* Valeur à transmettre */ + +#define KAITAI_META_ID_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + id, py_kaitai_meta, \ + "Identifier for the Kaitai definition, as a string" \ + " value or *None* if any." \ +) + + meta = G_KAITAI_META(pygobject_get(self)); + + id = g_kaitai_meta_get_id(meta); + + if (id != NULL) + result = PyUnicode_FromString(id); + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation humaine d'une définiton Kaitai. * +* * +* Retour : Intitulé de définition OU None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_meta_get_title(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiMeta *meta; /* Version native de l'objet */ + const char *title; /* Valeur à transmettre */ + +#define KAITAI_META_TITLE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + title, py_kaitai_meta, \ + "Humain description for the Kaitai definition, as a" \ + " string value or *None* if any." \ +) + + meta = G_KAITAI_META(pygobject_get(self)); + + title = g_kaitai_meta_get_title(meta); + + if (title != NULL) + result = PyUnicode_FromString(title); + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation humaine d'une définiton Kaitai. * +* * +* Retour : Intitulé de définition OU None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_meta_get_endian(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiMeta *meta; /* Version native de l'objet */ + SourceEndian endian; /* Valeur à transmettre */ + +#define KAITAI_META_ENDIAN_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + endian, py_kaitai_meta, \ + "Default endianness for the Kaitai definition, as a" \ + " pychrysalide.analysis.BinContent.SourceEndian value." \ +) + + meta = G_KAITAI_META(pygobject_get(self)); + + endian = g_kaitai_meta_get_endian(meta); + + result = cast_with_constants_group_from_type(get_python_binary_content_type(), "SourceEndian", endian); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_meta_type(void) +{ + static PyMethodDef py_kaitai_meta_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_meta_getseters[] = { + KAITAI_META_ID_ATTRIB, + KAITAI_META_TITLE_ATTRIB, + KAITAI_META_ENDIAN_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_meta_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiMeta", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_META_DOC, + + .tp_methods = py_kaitai_meta_methods, + .tp_getset = py_kaitai_meta_getseters, + + .tp_init = py_kaitai_meta_init, + .tp_new = py_kaitai_meta_new + + }; + + return &py_kaitai_meta_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiMeta. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_meta_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiMeta' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_meta_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_META, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en description globale Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_meta(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_meta_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai global description"); + break; + + case 1: + *((GKaitaiMeta **)dst) = G_KAITAI_META(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/meta.h b/plugins/kaitai/python/parsers/meta.h new file mode 100644 index 0000000..383cad9 --- /dev/null +++ b/plugins/kaitai/python/parsers/meta.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * meta.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/meta.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_META_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_META_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_meta_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiMeta'. */ +bool ensure_python_kaitai_meta_is_registered(void); + +/* Tente de convertir en description globale Kaitai. */ +int convert_to_kaitai_meta(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_META_H */ diff --git a/plugins/kaitai/python/parsers/module.c b/plugins/kaitai/python/parsers/module.c new file mode 100644 index 0000000..549f728 --- /dev/null +++ b/plugins/kaitai/python/parsers/module.c @@ -0,0 +1,124 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire parsers en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "attribute.h" +#include "enum.h" +#include "instance.h" +#include "meta.h" +#include "struct.h" +#include "type.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.kaitai.parsers' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_parsers_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_KAITAI_PARSERS_DOC \ + "This module provides implementation for several Kaitai" \ + " definitions parsers." + + static PyModuleDef py_chrysalide_kaitai_parsers_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.kaitai.parsers", + .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_PARSERS_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + module = build_python_module(super, &py_chrysalide_kaitai_parsers_module); + + result = (module != NULL); + + assert(result); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.kaitai.parsers'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_kaitai_parsers_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_kaitai_attribute_is_registered(); + if (result) result = ensure_python_kaitai_enum_is_registered(); + if (result) result = ensure_python_kaitai_instance_is_registered(); + if (result) result = ensure_python_kaitai_meta_is_registered(); + if (result) result = ensure_python_kaitai_structure_is_registered(); + if (result) result = ensure_python_kaitai_type_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/kaitai/python/parsers/module.h b/plugins/kaitai/python/parsers/module.h new file mode 100644 index 0000000..d0fdd66 --- /dev/null +++ b/plugins/kaitai/python/parsers/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire parsers en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.kaitai.parsers' au module Python. */ +bool add_kaitai_parsers_module(void); + +/* Intègre les objets du module 'plugins.kaitai.parsers'. */ +bool populate_kaitai_parsers_module(void); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H */ diff --git a/plugins/kaitai/python/parsers/struct.c b/plugins/kaitai/python/parsers/struct.c new file mode 100644 index 0000000..900cd1b --- /dev/null +++ b/plugins/kaitai/python/parsers/struct.c @@ -0,0 +1,376 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * struct.h - équivalent Python du fichier "plugins/kaitai/struct.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "struct.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> + + +#include "../parser.h" +#include "../../parsers/struct-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_structure, G_TYPE_KAITAI_STRUCT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_structure_init(PyObject *, PyObject *, PyObject *); + +/* Parcourt un contenu binaire selon une description Kaitai. */ +static PyObject *py_kaitai_structure_parse(PyObject *, PyObject *); + +/* Fournit la désignation humaine d'une définiton Kaitai. */ +static PyObject *py_kaitai_structure_get_meta(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_structure_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *text; /* Contenu de règles à traiter */ + const char *filename; /* Fichier de définitions */ + int ret; /* Bilan de lecture des args. */ + GKaitaiStruct *kstruct; /* Création GLib à transmettre */ + + static char *kwlist[] = { "text", "filename", NULL }; + +#define KAITAI_STRUCT_DOC \ + "KaitaiStruct is the class providing support for parsing binary contents" \ + " using a special declarative language." \ + "\n" \ + "Instances can be created using one of the following constructors:\n" \ + "\n" \ + " KaitaiStruct(text=str)" \ + "\n" \ + " KaitaiStruct(filename=str)" \ + "\n" \ + "Where *text* is a string containg a markup content to parse; the" \ + " *filename* argument is an alternative string for a path pointing to the" \ + " same kind of content. This path can be a real filename or a resource" \ + " URI." \ + "\n" \ + "It is the Python bindings for a C implementation of the specifications" \ + " described at http://kaitai.io/." + + /* Récupération des paramètres */ + + text = NULL; + filename = NULL; + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, &text, &filename); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + kstruct = G_KAITAI_STRUCT(pygobject_get(self)); + + if (text != NULL) + { + if (!g_kaitai_structure_create_from_text(kstruct, text)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai structure.")); + return -1; + } + + } + + else if (filename != NULL) + { + if (!g_kaitai_structure_create_from_file(kstruct, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai structure.")); + return -1; + } + + } + + else + { + PyErr_SetString(PyExc_ValueError, _("Unable to create empty Kaitai structure.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'interpréteur Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Parcourt un contenu binaire selon une description Kaitai. * +* * +* Retour : Arborescence d'éléments rencontrés selon les spécifications. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_structure_parse(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + GBinContent *content; /* Contenu binaire à traiter */ + int ret; /* Bilan de lecture des args. */ + GKaitaiStruct *kstruct; /* Interpréteur Kaitai courant */ + GMatchRecord *record; /* Ensemble de correspondances */ + +#define KAITAI_STRUCTURE_PARSE_METHOD PYTHON_METHOD_DEF \ +( \ + parse, "$self, content", \ + METH_VARARGS, py_kaitai_structure, \ + "Parse a binary content with the loaded specifications." \ + "\n" \ + "The content has to be a pychrysalide.analysis.BinContent instance.\n" \ + "\n" \ + "The result is *None* if the parsing failed, or a" \ + " pychrysalide.plugins.kaitai.MatchRecord object for each attribute" \ + " met." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_binary_content, &content); + if (!ret) return NULL; + + kstruct = G_KAITAI_STRUCT(pygobject_get(self)); + + record = g_kaitai_structure_parse(kstruct, content); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation humaine d'une définiton Kaitai. * +* * +* Retour : Intitulé de définition OU None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_structure_get_meta(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiStruct *kstruct; /* Version native de l'objet */ + GKaitaiMeta *meta; /* Informations à transmettre */ + +#define KAITAI_STRUCTURE_META_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + meta, py_kaitai_structure, \ + "Global description provided for the Kaitai definition, as a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiMeta instance." \ +) + + kstruct = G_KAITAI_STRUCT(pygobject_get(self)); + + meta = g_kaitai_structure_get_meta(kstruct); + + if (meta != NULL) + { + result = pygobject_new(G_OBJECT(meta)); + g_object_unref(G_OBJECT(meta)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_structure_type(void) +{ + static PyMethodDef py_kaitai_structure_methods[] = { + KAITAI_STRUCTURE_PARSE_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_structure_getseters[] = { + KAITAI_STRUCTURE_META_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_structure_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiStruct", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_STRUCT_DOC, + + .tp_methods = py_kaitai_structure_methods, + .tp_getset = py_kaitai_structure_getseters, + + .tp_init = py_kaitai_structure_init, + .tp_new = py_kaitai_structure_new + + }; + + return &py_kaitai_structure_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiStruct.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_structure_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiStruct' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_structure_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_parser_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_STRUCT, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en structure de données Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_structure(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_structure_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai structure"); + break; + + case 1: + *((GKaitaiStruct **)dst) = G_KAITAI_STRUCT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/struct.h b/plugins/kaitai/python/parsers/struct.h new file mode 100644 index 0000000..872f744 --- /dev/null +++ b/plugins/kaitai/python/parsers/struct.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * struct.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/struct.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_structure_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiStruct'. */ +bool ensure_python_kaitai_structure_is_registered(void); + +/* Tente de convertir en structure de données Kaitai. */ +int convert_to_kaitai_structure(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H */ diff --git a/plugins/kaitai/python/parsers/type.c b/plugins/kaitai/python/parsers/type.c new file mode 100644 index 0000000..64a3419 --- /dev/null +++ b/plugins/kaitai/python/parsers/type.c @@ -0,0 +1,278 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.h - équivalent Python du fichier "plugins/kaitai/parsers/type.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "type.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "struct.h" +#include "../../parsers/type-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_type, G_TYPE_KAITAI_TYPE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_type_init(PyObject *, PyObject *, PyObject *); + +/* Indique le nom de scène du type représenté. */ +static PyObject *py_kaitai_type_get_name(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_type_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiType *attrib; /* Création GLib à transmettre */ + +#define KAITAI_TYPE_DOC \ + "The KaitaiType class provides support for user-defined type used in" \ + " Kaitai definitions.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiType(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the TypesSpec" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + attrib = G_KAITAI_TYPE(pygobject_get(self)); + + if (!g_kaitai_type_create(attrib, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai type.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le nom de scène du type représenté. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_type_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiType *type; /* Version native du type */ + const char *name; /* Désignation à transmettre */ + +#define KAITAI_TYPE_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_kaitai_type, \ + "Name of the user-defined type, provided as a unique" \ + " string value." \ +) + + type = G_KAITAI_TYPE(pygobject_get(self)); + + name = g_kaitai_type_get_name(type); + assert(name != NULL); + + result = PyUnicode_FromString(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_type_type(void) +{ + static PyMethodDef py_kaitai_type_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_type_getseters[] = { + KAITAI_TYPE_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_type_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiType", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_TYPE_DOC, + + .tp_methods = py_kaitai_type_methods, + .tp_getset = py_kaitai_type_getseters, + + .tp_init = py_kaitai_type_init, + .tp_new = py_kaitai_type_new, + + }; + + return &py_kaitai_type_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....parsers.KaitaiType. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_type_is_registered(void) +{ + PyTypeObject *type; /* Type 'KaitaiType' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_type_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_structure_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_TYPE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en type particulier pour Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_type(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_type_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai type"); + break; + + case 1: + *((GKaitaiType **)dst) = G_KAITAI_TYPE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/type.h b/plugins/kaitai/python/parsers/type.h new file mode 100644 index 0000000..320bc71 --- /dev/null +++ b/plugins/kaitai/python/parsers/type.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/type.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_type_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiType'. */ +bool ensure_python_kaitai_type_is_registered(void); + +/* Tente de convertir en type particulier pour Kaitai. */ +int convert_to_kaitai_type(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H */ diff --git a/plugins/kaitai/python/record.c b/plugins/kaitai/python/record.c new file mode 100644 index 0000000..4194a9a --- /dev/null +++ b/plugins/kaitai/python/record.c @@ -0,0 +1,420 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * record.h - équivalent Python du fichier "plugins/kaitai/record.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "record.h" + + +#include <pygobject.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/arch/vmpa.h> + + +#include "parser.h" +#include "../record.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(match_record, G_TYPE_MATCH_RECORD, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_match_record_init(PyObject *, PyObject *, PyObject *); + +/* Modifie la référence au créateur de la correspondance. */ +static int py_match_record_set_creator(PyObject *, PyObject *, void *); + +/* Renvoie vers le lecteur à l'origine de la correspondance. */ +static PyObject *py_match_record_get_creator(PyObject *, void *); + +/* Fournit le contenu lié à une correspondance établie. */ +static PyObject *py_match_record_get_content(PyObject *, void *); + +/* Calcule ou fournit la zone couverte par une correspondance. */ +static PyObject *py_match_record_get_range(PyObject *, void *); + +/* Lit les octets bruts couverts par une correspondance. */ +static PyObject *py_match_record_get_raw_bytes(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_match_record_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define MATCH_RECORD_DOC \ + "MatchRecord is an abstract class providing mainly location and raw" \ + " data of an area which has matched a part of a binary content." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = correspondance à manipuler. * +* value = lecteur à l'origine de la correspondance. * +* closure = adresse non utilisée ici. * +* * +* Description : Modifie la référence au créateur de la correspondance. * +* * +* Retour : Bilan de la définition. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_match_record_set_creator(PyObject *self, PyObject *value, void *closure) +{ + int result; /* Bilan à renvoyer */ + GMatchRecord *record; /* Version GLib de l'objet */ + GKaitaiParser *parser; /* Lecteur à l'origine */ + + record = G_MATCH_RECORD(pygobject_get(self)); + + if (!convert_to_kaitai_parser(value, &parser)) + result = -1; + + else + { + g_match_record_fix_creator(record, parser); + result = 0; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = correspondance à manipuler. * +* closure = adresse non utilisée ici. * +* * +* Description : Renvoie vers le lecteur à l'origine de la correspondance. * +* * +* Retour : Lecteur à l'origine de la création. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_match_record_get_creator(PyObject *self, void *closure) +{ + PyObject *result; /* Instance à retourner */ + GMatchRecord *record; /* Version GLib de l'objet */ + GKaitaiParser *parser; /* Lecteur à l'origine */ + +#define MATCH_RECORD_CREATOR_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + creator, py_match_record, \ + "Provide or define the pychrysalide.plugins.kaitai.KaitaiParser instance" \ + " which has created the record.\n" \ + "\n" \ + "This field should not be defined after the record creation in most cases." \ +) + + record = G_MATCH_RECORD(pygobject_get(self)); + + parser = g_match_record_get_creator(record); + + result = pygobject_new(G_OBJECT(parser)); + g_object_unref(parser); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit le contenu lié à une correspondance établie. * +* * +* Retour : Contenu binaire associé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_match_record_get_content(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GMatchRecord *record; /* Conservation à consulter */ + GBinContent *content; /* Contenu associé */ + +#define MATCH_RECORD_CONTENT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + content, py_match_record, \ + "pychrysalide.analysis.BinContent instance linked to" \ + " the match record." \ +) + + record = G_MATCH_RECORD(pygobject_get(self)); + content = g_match_record_get_content(record); + + if (content != NULL) + { + result = pygobject_new(G_OBJECT(content)); + g_object_unref(G_OBJECT(content)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Calcule ou fournit la zone couverte par une correspondance. * +* * +* Retour : Zone de couverture déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_match_record_get_range(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GMatchRecord *record; /* Conservation à consulter */ + mrange_t range; /* Couverture courante */ + +#define MATCH_RECORD_RANGE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + range, py_match_record, \ + "Area of the matched data for the parsed attribute" \ + " against a given binary content.\n" \ + "\n" \ + "This property is a pychrysalide.arch.mrange instance." \ +) + + record = G_MATCH_RECORD(pygobject_get(self)); + g_match_record_get_range(record, &range); + + result = build_from_internal_mrange(&range); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit les octets bruts couverts par une correspondance. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_match_record_get_raw_bytes(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GMatchRecord *record; /* Conservation à consulter */ + bin_t *out; /* Données brutes à transmettre*/ + size_t len; /* Quantité de ces données */ + +#define MATCH_RECORD_RAW_BYTES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + raw_bytes, py_match_record, \ + "Raw bytes from the area covered by the record." \ +) + + record = G_MATCH_RECORD(pygobject_get(self)); + + g_match_record_read_raw_bytes(record, &out, &len); + + result = PyBytes_FromStringAndSize((char *)out, len); + free(out); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_match_record_type(void) +{ + static PyMethodDef py_match_record_methods[] = { + { NULL } + }; + + static PyGetSetDef py_match_record_getseters[] = { + MATCH_RECORD_CREATOR_ATTRIB, + MATCH_RECORD_CONTENT_ATTRIB, + MATCH_RECORD_RANGE_ATTRIB, + MATCH_RECORD_RAW_BYTES_ATTRIB, + { NULL } + }; + + static PyTypeObject py_match_record_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.MatchRecord", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = MATCH_RECORD_DOC, + + .tp_methods = py_match_record_methods, + .tp_getset = py_match_record_getseters, + + .tp_init = py_match_record_init, + .tp_new = py_match_record_new, + + }; + + return &py_match_record_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...MatchRecord. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_match_record_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'MatchRecord' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_match_record_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_MATCH_RECORD, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en conservation de correspondance. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_match_record(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_match_record_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to match record"); + break; + + case 1: + *((GMatchRecord **)dst) = G_MATCH_RECORD(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/record.h b/plugins/kaitai/python/record.h new file mode 100644 index 0000000..edf75fc --- /dev/null +++ b/plugins/kaitai/python/record.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * record.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/record.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORD_H +#define _PLUGINS_KAITAI_PYTHON_RECORD_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_match_record_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.MatchRecord'. */ +bool ensure_python_match_record_is_registered(void); + +/* Tente de convertir en conservation de correspondance. */ +int convert_to_match_record(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORD_H */ diff --git a/plugins/kaitai/python/records/Makefile.am b/plugins/kaitai/python/records/Makefile.am new file mode 100644 index 0000000..1413228 --- /dev/null +++ b/plugins/kaitai/python/records/Makefile.am @@ -0,0 +1,18 @@ + +noinst_LTLIBRARIES = libkaitaipythonrecords.la + +libkaitaipythonrecords_la_SOURCES = \ + empty.h empty.c \ + group.h group.c \ + item.h item.c \ + list.h list.c \ + module.h module.c \ + value.h value.c + +libkaitaipythonrecords_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaipythonrecords_la_SOURCES:%c=) diff --git a/plugins/kaitai/python/records/empty.c b/plugins/kaitai/python/records/empty.c new file mode 100644 index 0000000..9861a39 --- /dev/null +++ b/plugins/kaitai/python/records/empty.c @@ -0,0 +1,286 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * empty.c - équivalent Python du fichier "plugins/kaitai/parsers/empty.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "empty.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> + + +#include "../parser.h" +#include "../record.h" +#include "../../records/empty-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_empty, G_TYPE_RECORD_EMPTY); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_empty_init(PyObject *, PyObject *, PyObject *); + +/* Produit une absence de valeur pour la correspondance. */ +static PyObject *py_record_empty_get_value(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_empty_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiParser *parser; /* Analyseur défini créateur */ + GBinContent *content; /* Contenu binaire manipulé */ + vmpa2t *pos; /* Tête de lecture courante */ + int ret; /* Bilan de lecture des args. */ + GRecordEmpty *empty; /* Création GLib à transmettre */ + +#define RECORD_EMPTY_DOC \ + "The RecordEmpty object reflects absolutely no match and should only get" \ + " in some rare cases.\n" \ + "\n" \ + "Instances can be created using following constructor:\n" \ + "\n" \ + " RecordEmpty(parser, content, pos)" \ + "\n" \ + "Where *parser* is the creator of the record, as a" \ + " pychrysalide.plugins.kaitai.KaitaiParser instance, *content* is a" \ + " pychrysalide.analysis.BinContent instance providing the processed data" \ + " and *pos* defines the current reading location, as a" \ + " pychrysalide.arch.vmpa value." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&O&", + convert_to_kaitai_parser, &parser, + convert_to_binary_content, &content, + convert_any_to_vmpa, &pos); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + empty = G_RECORD_EMPTY(pygobject_get(self)); + + if (!g_record_empty_create(empty, parser, content, pos)) + { + clean_vmpa_arg(pos); + + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream.")); + return -1; + + } + + clean_vmpa_arg(pos); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Produit une absence de valeur pour la correspondance. * +* * +* Retour : None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_empty_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + +#define RECORD_EMPTY_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_record_empty, \ + "Always *None*.\n" \ + "\n" \ + "This attribute is only provided to mimic other" \ + " record types." \ +) + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_empty_type(void) +{ + static PyMethodDef py_record_empty_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_empty_getseters[] = { + RECORD_EMPTY_VALUE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_record_empty_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordEmpty", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_EMPTY_DOC, + + .tp_methods = py_record_empty_methods, + .tp_getset = py_record_empty_getseters, + + .tp_init = py_record_empty_init, + .tp_new = py_record_empty_new, + + }; + + return &py_record_empty_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...records.RecordEmpty. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_empty_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordEmpty' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_empty_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_EMPTY, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en zone de correspondance vide. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_empty(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_empty_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record empty"); + break; + + case 1: + *((GRecordEmpty **)dst) = G_RECORD_EMPTY(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/empty.h b/plugins/kaitai/python/records/empty.h new file mode 100644 index 0000000..ecd5fc9 --- /dev/null +++ b/plugins/kaitai/python/records/empty.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * empty.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/empty.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_empty_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordEmpty'. */ +bool ensure_python_record_empty_is_registered(void); + +/* Tente de convertir en zone de correspondance vide. */ +int convert_to_record_empty(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H */ diff --git a/plugins/kaitai/python/records/group.c b/plugins/kaitai/python/records/group.c new file mode 100644 index 0000000..a050043 --- /dev/null +++ b/plugins/kaitai/python/records/group.c @@ -0,0 +1,305 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * group.h - équivalent Python du fichier "plugins/kaitai/parsers/group.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "group.h" + + +#include <pygobject.h> +#include <string.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> + + +#include "../record.h" +#include "../parsers/struct.h" +#include "../../records/group-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_group, G_TYPE_RECORD_GROUP); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_group_init(PyObject *, PyObject *, PyObject *); + +/* Assure l'encadrement des accès aux champs d'une séquence. */ +static PyObject *py_record_group_getattr(PyObject *, char *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_group_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiStruct *kstruct; /* Séquence définie créatrice */ + GBinContent *content; /* Contenu binaire analysé */ + int ret; /* Bilan de lecture des args. */ + GRecordGroup *group; /* Création GLib à transmettre */ + +#define RECORD_GROUP_DOC \ + "The RecordGroup class stores a map of parsed attributes with their" \ + " relative values. Each of theses Kaitai attributes can be accessed as" \ + " usual Python attribute.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordGroup(kstruct, content)" \ + "\n" \ + "Where the *kstruct* refers to a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiStructure instance as the" \ + " creator of the newly created object, and *content* points to a" \ + " pychrysalide.analysis.BinContent instance." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&", + convert_to_kaitai_structure, &kstruct, + convert_to_binary_content, &content); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + group = G_RECORD_GROUP(pygobject_get(self)); + + if (!g_record_group_create(group, kstruct, content)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record group.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = structure C convertie en Python. * +* name = nom du champ auquel un accès est demandé. * +* * +* Description : Assure l'encadrement des accès aux champs d'une séquence. * +* * +* Retour : Valeur du champ demandé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_group_getattr(PyObject *self, char *name) +{ + PyObject *result; /* Elément à retourner */ + GRecordGroup *group; /* Version native de l'objet */ + GMatchRecord *found; /* Sous-élément identifié */ + PyObject *w; /* Conversion du nom de champ */ + PyTypeObject *tp; /* Type de l'objet manipulé */ + + group = G_RECORD_GROUP(pygobject_get(self)); + + found = g_match_record_find_by_name(G_MATCH_RECORD(group), name, strlen(name), DIRECT_SEARCH_DEEP_LEVEL); + + if (found != NULL) + { + result = pygobject_new(G_OBJECT(found)); + g_object_unref(G_OBJECT(found)); + } + + else + { + w = PyUnicode_InternFromString(name); + if (w == NULL) return NULL; + + tp = Py_TYPE(self); + + if (tp->tp_base->tp_getattro != NULL) + result = tp->tp_base->tp_getattro(self, w); + + else + { + PyErr_Format(PyExc_AttributeError, + "type object '%.50s' has no attribute '%U'", + tp->tp_name, name); + result = NULL; + } + + Py_DECREF(w); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_group_type(void) +{ + static PyMethodDef py_record_group_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_group_getseters[] = { + { NULL } + }; + + static PyTypeObject py_record_group_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordGroup", + .tp_basicsize = sizeof(PyGObject), + + .tp_getattr = py_record_group_getattr, + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_GROUP_DOC, + + .tp_methods = py_record_group_methods, + .tp_getset = py_record_group_getseters, + + .tp_init = py_record_group_init, + .tp_new = py_record_group_new, + + }; + + return &py_record_group_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...records.RecordGroup. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_group_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordGroup' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_group_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_GROUP, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en correspondances attribut/binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_group(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_group_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record group"); + break; + + case 1: + *((GRecordGroup **)dst) = G_RECORD_GROUP(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/group.h b/plugins/kaitai/python/records/group.h new file mode 100644 index 0000000..3e12ffc --- /dev/null +++ b/plugins/kaitai/python/records/group.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * group.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/group.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_group_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordGroup'. */ +bool ensure_python_record_group_is_registered(void); + +/* Tente de convertir en correspondances attribut/binaire. */ +int convert_to_record_group(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H */ diff --git a/plugins/kaitai/python/records/item.c b/plugins/kaitai/python/records/item.c new file mode 100644 index 0000000..84c2c58 --- /dev/null +++ b/plugins/kaitai/python/records/item.c @@ -0,0 +1,394 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - équivalent Python du fichier "plugins/kaitai/parsers/item.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "item.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> + + +#include "../record.h" +#include "../parsers/attribute.h" +#include "../../records/item-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_item, G_TYPE_RECORD_ITEM); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_item_init(PyObject *, PyObject *, PyObject *); + +/* Lit la série d'octets d'un élément Kaitai entier représenté. */ +static PyObject *py_record_item_get_truncated_bytes(PyObject *, void *); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +static PyObject *py_record_item_get_value(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_item_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiAttribute *attrib; /* Attribut défini créateur */ + GBinContent *content; /* Contenu binaire analysé */ + mrange_t range; /* Espace couvert */ + SourceEndian endian; /* Boutisme à observer */ + int ret; /* Bilan de lecture des args. */ + GRecordItem *item; /* Création GLib à transmettre */ + +#define RECORD_ITEM_DOC \ + "The RecordItem class remembers a match between a described attribute and" \ + " its concret value read from parsed binary data." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordItem(content, range, endian, attrib)" \ + "\n" \ + "Where the *attrib* arguments refers to a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance as the" \ + " creator of the newly created object, *content* points to a" \ + " pychrysalide.analysis.BinContent instance, *range* is a" \ + " pychrysalide.arch.mrange object, *endian* states with a" \ + " pychrysalide.analysis.BinContent.SourceEndian hint the endianness used" \ + " to read integer values." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&O&", + convert_to_kaitai_attribute, &attrib, + convert_to_binary_content, &content, + convert_any_to_mrange, &range, + convert_to_binary_content, &endian); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + item = G_RECORD_ITEM(pygobject_get(self)); + + if (!g_record_item_create(item, attrib, content, &range, endian)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record item.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit la série d'octets d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_item_get_truncated_bytes(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GRecordItem *item; /* Version native de l'élément */ + bool status; /* Bilan d'opération */ + bin_t *out; /* Données brutes à transmettre*/ + size_t len; /* Quantité de ces données */ + +#define RECORD_ITEM_TRUNCATED_BYTES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + truncated_bytes, py_record_item, \ + "Raw bytes carried by the item (truncated if a separator" \ + " is defined in the linked attribute), or None if irrelevant" \ + " regarding to the type of the attribute." \ +) + + item = G_RECORD_ITEM(pygobject_get(self)); + + status = g_record_item_get_truncated_bytes(item, &out, &len); + + if (status) + { + result = PyBytes_FromStringAndSize((char *)out, len); + free(out); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_item_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GRecordItem *item; /* Version native de l'élément */ + resolved_value_t resolved; /* Valeur sous forme générique */ + bool status; /* Bilan d'opération */ + +#define RECORD_ITEM_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_record_item, \ + "Carried value (as integer, bytes), or None in case of error." \ +) + + result = NULL; + + item = G_RECORD_ITEM(pygobject_get(self)); + + status = g_record_item_get_value(item, &resolved); + + if (status) + switch (resolved.type) + { + case GVT_ERROR: + assert(false); + PyErr_Format(PyExc_RuntimeError, + _("Error got while parsing Kaitai definition should not have been exported!")); + result = NULL; + break; + + case GVT_UNSIGNED_INTEGER: + result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer); + break; + + case GVT_SIGNED_INTEGER: + result = PyLong_FromLongLong(resolved.signed_integer); + break; + + case GVT_FLOAT: + result = PyFloat_FromDouble(resolved.floating_number); + break; + + case GVT_BOOLEAN: + result = resolved.status ? Py_True : Py_False; + Py_INCREF(result); + break; + + case GVT_BYTES: + result = PyBytes_FromStringAndSize(resolved.bytes.data, resolved.bytes.len); + exit_szstr(&resolved.bytes); + break; + + case GVT_ARRAY: + result = pygobject_new(G_OBJECT(resolved.array)); + break; + + case GVT_RECORD: + result = pygobject_new(G_OBJECT(resolved.record)); + break; + + case GVT_STREAM: + result = pygobject_new(G_OBJECT(resolved.stream)); + break; + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_item_type(void) +{ + static PyMethodDef py_record_item_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_item_getseters[] = { + RECORD_ITEM_TRUNCATED_BYTES_ATTRIB, + RECORD_ITEM_VALUE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_record_item_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordItem", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_ITEM_DOC, + + .tp_methods = py_record_item_methods, + .tp_getset = py_record_item_getseters, + + .tp_init = py_record_item_init, + .tp_new = py_record_item_new, + + }; + + return &py_record_item_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....records.RecordItem. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_item_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordItem' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_item_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_ITEM, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en correspondance attribut/binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_item(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_item_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record item"); + break; + + case 1: + *((GRecordItem **)dst) = G_RECORD_ITEM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/item.h b/plugins/kaitai/python/records/item.h new file mode 100644 index 0000000..bde8a55 --- /dev/null +++ b/plugins/kaitai/python/records/item.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/item.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_item_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordItem'. */ +bool ensure_python_record_item_is_registered(void); + +/* Tente de convertir en correspondance attribut/binaire. */ +int convert_to_record_item(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H */ diff --git a/plugins/kaitai/python/records/list.c b/plugins/kaitai/python/records/list.c new file mode 100644 index 0000000..d2eecbb --- /dev/null +++ b/plugins/kaitai/python/records/list.c @@ -0,0 +1,336 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - équivalent Python du fichier "plugins/kaitai/parsers/list.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "list.h" + + +#include <pygobject.h> +#include <string.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> + + +#include "../record.h" +#include "../parsers/attribute.h" +#include "../../records/list-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_list, G_TYPE_RECORD_LIST); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_list_init(PyObject *, PyObject *, PyObject *); + +/* Dénombre le nombre de correspondances enregistrées. */ +static Py_ssize_t py_record_list_sq_length(PyObject *); + +/* Fournit un élément ciblé dans la liste de correspondances. */ +static PyObject *py_record_list_sq_item(PyObject *, Py_ssize_t); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_list_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int result; /* Bilan à retourner */ + GKaitaiAttribute *attrib; /* Attribut défini créateur */ + GBinContent *content; /* Contenu binaire analysé */ + vmpa2t *addr; /* Adresse de symbole à ajouter*/ + int ret; /* Bilan de lecture des args. */ + GRecordList *list; /* Création GLib à transmettre */ + +#define RECORD_LIST_DOC \ + "The RecordList class collects a list of parsed attributes with their" \ + " relative values. Each of theses Kaitai attributes can be accessed as" \ + " subscriptable Python attribute.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordList(content, attrib)" \ + "\n" \ + "Where the *attrib* argument refers to the" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance used to" \ + " create each record contained by the list and *content* points to a" \ + " pychrysalide.analysis.BinContent instance." + + result = 0; + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&", + convert_to_kaitai_attribute, &attrib, + convert_to_binary_content, &content, + convert_any_to_vmpa, &addr); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) + { + result = -1; + goto exit; + } + + /* Eléments de base */ + + list = G_RECORD_LIST(pygobject_get(self)); + + if (!g_record_list_create(list, attrib, content, addr)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record list.")); + result = -1; + goto exit; + } + + exit: + + clean_vmpa_arg(addr); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance Python manipulée. * +* * +* Description : Dénombre le nombre de correspondances enregistrées. * +* * +* Retour : Taille de la liste représentée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static Py_ssize_t py_record_list_sq_length(PyObject *self) +{ + Py_ssize_t result; /* Quantité à retourner */ + GRecordList *list; /* Version native de l'objet */ + + list = G_RECORD_LIST(pygobject_get(self)); + + result = g_record_list_count_records(list); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = structure C convertie en Python. * +* index = indice de la correspondance visée. * +* * +* Description : Fournit un élément ciblé dans la liste de correspondances. * +* * +* Retour : Instance de correspondance particulière, voire None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_list_sq_item(PyObject *self, Py_ssize_t index) +{ + PyObject *result; /* Instance à retourner */ + GRecordList *list; /* Version native de l'objet */ + GMatchRecord *record; /* Correspondance retrouvée */ + + list = G_RECORD_LIST(pygobject_get(self)); + + record = g_record_list_get_record(list, index); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_list_type(void) +{ + static PySequenceMethods py_record_list_sequence_methods = { + + .sq_length = py_record_list_sq_length, + .sq_item = py_record_list_sq_item, + + }; + + static PyMethodDef py_record_list_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_list_getseters[] = { + { NULL } + }; + + static PyTypeObject py_record_list_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordList", + .tp_basicsize = sizeof(PyGObject), + + .tp_as_sequence = &py_record_list_sequence_methods, + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_LIST_DOC, + + .tp_methods = py_record_list_methods, + .tp_getset = py_record_list_getseters, + + .tp_init = py_record_list_init, + .tp_new = py_record_list_new, + + }; + + return &py_record_list_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....records.RecordList. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_list_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordList' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_list_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_LIST, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en correspondance attribut/binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_list(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_list_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record list"); + break; + + case 1: + *((GRecordList **)dst) = G_RECORD_LIST(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/list.h b/plugins/kaitai/python/records/list.h new file mode 100644 index 0000000..53572a9 --- /dev/null +++ b/plugins/kaitai/python/records/list.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/list.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_list_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordList'. */ +bool ensure_python_record_list_is_registered(void); + +/* Tente de convertir en correspondance attribut/binaire. */ +int convert_to_record_list(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H */ diff --git a/plugins/kaitai/python/records/module.c b/plugins/kaitai/python/records/module.c new file mode 100644 index 0000000..ea33c31 --- /dev/null +++ b/plugins/kaitai/python/records/module.c @@ -0,0 +1,122 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire records en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "empty.h" +#include "group.h" +#include "item.h" +#include "list.h" +#include "value.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.kaitai.records' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_records_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_KAITAI_RECORDS_DOC \ + "This module is providing objects used to link structure" \ + " definitions with their data." + + static PyModuleDef py_chrysalide_kaitai_records_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.kaitai.records", + .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_RECORDS_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + module = build_python_module(super, &py_chrysalide_kaitai_records_module); + + result = (module != NULL); + + assert(result); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.kaitai.records'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_kaitai_records_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_record_empty_is_registered(); + if (result) result = ensure_python_record_group_is_registered(); + if (result) result = ensure_python_record_item_is_registered(); + if (result) result = ensure_python_record_list_is_registered(); + if (result) result = ensure_python_record_value_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/kaitai/python/records/module.h b/plugins/kaitai/python/records/module.h new file mode 100644 index 0000000..ff631dc --- /dev/null +++ b/plugins/kaitai/python/records/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire records en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.kaitai.records' au module Python. */ +bool add_kaitai_records_module(void); + +/* Intègre les objets du module 'plugins.kaitai.records'. */ +bool populate_kaitai_records_module(void); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H */ diff --git a/plugins/kaitai/python/records/value.c b/plugins/kaitai/python/records/value.c new file mode 100644 index 0000000..bd4ad74 --- /dev/null +++ b/plugins/kaitai/python/records/value.c @@ -0,0 +1,335 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * value.c - équivalent Python du fichier "plugins/kaitai/parsers/value.c" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "value.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> + + +#include "../record.h" +#include "../scope.h" +#include "../parsers/instance.h" +#include "../../records/value-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_value, G_TYPE_RECORD_VALUE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_value_init(PyObject *, PyObject *, PyObject *); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +static PyObject *py_record_value_get_value(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_value_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiInstance *inst; /* Instance définie créatrice */ + kaitai_scope_t *locals; /* Environnement local */ + int ret; /* Bilan de lecture des args. */ + GRecordValue *value; /* Création GLib à transmettre */ + +#define RECORD_VALUE_DOC \ + "The RecordValue class stores a link to an instance used to compute a" \ + " given value." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordValue(inst, locals)" \ + "\n" \ + "Where the *inst* arguments refers to a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiInstance instance as the" \ + " creator of the newly created object, *locals* points to a" \ + " pychrysalide.plugins.kaitai.KaitaiScope structure used as current scope." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&", + convert_to_kaitai_instance, &inst, + convert_to_kaitai_scope, &locals); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + value = G_RECORD_VALUE(pygobject_get(self)); + + if (!g_record_value_create(value, inst, locals)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record value.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_value_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GRecordValue *value; /* Version native de l'élément */ + resolved_value_t resolved; /* Valeur sous forme générique */ + bool status; /* Bilan d'opération */ + +#define RECORD_VALUE_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_record_value, \ + "Carried value (as integer, bytes), or None in case of error." \ +) + + result = NULL; + + value = G_RECORD_VALUE(pygobject_get(self)); + + status = g_record_value_compute_and_aggregate_value(value, &resolved); + + if (status) + switch (resolved.type) + { + case GVT_ERROR: + assert(false); + PyErr_Format(PyExc_RuntimeError, + _("Error got while parsing Kaitai definition should not have been exported!")); + result = NULL; + break; + + case GVT_UNSIGNED_INTEGER: + result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer); + break; + + case GVT_SIGNED_INTEGER: + result = PyLong_FromLongLong(resolved.signed_integer); + break; + + case GVT_FLOAT: + result = PyFloat_FromDouble(resolved.floating_number); + break; + + case GVT_BOOLEAN: + result = resolved.status ? Py_True : Py_False; + Py_INCREF(result); + break; + + case GVT_BYTES: + result = PyBytes_FromStringAndSize(resolved.bytes.data, resolved.bytes.len); + exit_szstr(&resolved.bytes); + break; + + case GVT_ARRAY: + result = pygobject_new(G_OBJECT(resolved.array)); + break; + + case GVT_RECORD: + result = pygobject_new(G_OBJECT(resolved.record)); + break; + + case GVT_STREAM: + result = pygobject_new(G_OBJECT(resolved.stream)); + break; + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_value_type(void) +{ + static PyMethodDef py_record_value_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_value_getseters[] = { + RECORD_VALUE_VALUE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_record_value_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordValue", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_VALUE_DOC, + + .tp_methods = py_record_value_methods, + .tp_getset = py_record_value_getseters, + + .tp_init = py_record_value_init, + .tp_new = py_record_value_new, + + }; + + return &py_record_value_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...records.RecordValue. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_value_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordValue' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_value_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_VALUE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en valeur calculée. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_value(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_value_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record value"); + break; + + case 1: + *((GRecordValue **)dst) = G_RECORD_VALUE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/value.h b/plugins/kaitai/python/records/value.h new file mode 100644 index 0000000..16cadcb --- /dev/null +++ b/plugins/kaitai/python/records/value.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * value.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/value.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_VALUE_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_VALUE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_value_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordValue'. */ +bool ensure_python_record_value_is_registered(void); + +/* Tente de convertir en valeur calculée. */ +int convert_to_record_value(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_VALUE_H */ diff --git a/plugins/kaitai/python/scope.c b/plugins/kaitai/python/scope.c new file mode 100644 index 0000000..b11dc81 --- /dev/null +++ b/plugins/kaitai/python/scope.c @@ -0,0 +1,542 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope.c - équivalent Python du fichier "plugins/kaitai/scope.c" + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "scope.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "record.h" +#include "parsers/meta.h" +#include "../record.h" +#include "../parsers/meta.h" + + + +/* Rassemblement de données d'un paquet */ +typedef struct _py_kaitai_scope_t +{ + PyObject_HEAD /* A laisser en premier */ + + kaitai_scope_t *native; /* Tampon de données lié */ + +} py_kaitai_scope_t; + + +/* Libère de la mémoire un objet Python 'py_kaitai_scope_t'. */ +static void py_kaitai_scope_dealloc(py_kaitai_scope_t *); + +/* Initialise un objet Python de type 'py_kaitai_scope_t'. */ +static int py_kaitai_scope_init(py_kaitai_scope_t *, PyObject *, PyObject *); + +/* Conserve le souvenir de la dernière correspondance effectuée. */ +static PyObject *py_kaitai_scope_remember_last_record(PyObject *, PyObject *); + +/* Recherche la définition d'un type nouveau pour Kaitai. */ +static PyObject *py_kaitai_scope_find_sub_type(PyObject *, PyObject *); + +/* Retourne le souvenir d'une correspondance racine. */ +static PyObject *py_kaitai_scope_get_root_record(PyObject *, void *); + +/* Retourne le souvenir de la correspondance parente effectuée. */ +static PyObject *py_kaitai_scope_get_parent_record(PyObject *, void *); + +/* Retourne le souvenir de la dernière correspondance effectuée. */ +static PyObject *py_kaitai_scope_get_last_record(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à supprimer. * +* * +* Description : Libère de la mémoire un objet Python 'py_kaitai_scope_t'. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_kaitai_scope_dealloc(py_kaitai_scope_t *self) +{ + reset_record_scope(self->native); + + Py_TYPE(self)->tp_free((PyObject *)self); + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance d'objet à initialiser. * +* args = arguments passés pour l'appel. * +* kwds = mots clefs éventuellement fournis en complément. * +* * +* Description : Initialise un objet Python de type 'py_kaitai_scope_t'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_scope_init(py_kaitai_scope_t *self, PyObject *args, PyObject *kwds) +{ + int result; /* Bilan à retourner */ + GKaitaiMeta *meta; /* Informations globale */ + int ret; /* Bilan de lecture des args. */ + +#define KAITAI_SCOPE_DOC \ + "The KaitaiScope object stores a local environment which freezes" \ + " a particular state of the Kaitai parser. It allows the dynamic" \ + " resolving of values contained in a Kaitai expression.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiScope(meta)" \ + "\n" \ + "Where *meta* is a pychrysalide.plugins.kaitai.parsers.KaitaiMeta" \ + " instance pointing to global information about the Kaitai" \ + " definition." + + ret = PyArg_ParseTuple(args, "O&", convert_to_kaitai_meta, &meta); + if (!ret) return -1; + + self->native = malloc(sizeof(kaitai_scope_t)); + + init_record_scope(self->native, meta); + + result = 0; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à manipuler. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Conserve le souvenir de la dernière correspondance effectuée.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_remember_last_record(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + GMatchRecord *record; /* Correspondance à utiliser */ + int ret; /* Bilan de lecture des args. */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + +#define KAITAI_SCOPE_REMEMBER_LAST_RECORD_METHOD PYTHON_METHOD_DEF \ +( \ + remember_last_record, "$self, record, /", \ + METH_VARARGS, py_kaitai_scope, \ + "Store a record as the last parsed record.\n" \ + "\n" \ + "This *record* is expected to be a" \ + " pychrysalide.plugins.kaitai.MatchRecord instance." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_match_record, &record); + if (!ret) return NULL; + + locals = (py_kaitai_scope_t *)self; + + remember_last_record(locals->native, record); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à manipuler. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Recherche la définition d'un type nouveau pour Kaitai. * +* * +* Retour : Type prêt à emploi ou NULL si non trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_find_sub_type(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + const char *name; /* Désignation à retrouver */ + int ret; /* Bilan de lecture des args. */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GKaitaiType *type; /* Définition à identifier */ + +#define KAITAI_SCOPE_FIND_SUB_TYPE_METHOD PYTHON_METHOD_DEF \ +( \ + find_sub_type, "$self, name, /", \ + METH_VARARGS, py_kaitai_scope, \ + "Retrieve the type structure linked to a given name.\n" \ + "\n" \ + "This *name* has to be a string.\n" \ + "\n" \ + "The result is a known" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiType instance" \ + " or *None* if the name has not been registered during" \ + " the parsing." \ +) + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return NULL; + + locals = (py_kaitai_scope_t *)self; + + type = find_sub_type(locals->native, name); + + result = pygobject_new(G_OBJECT(type)); + g_object_unref(G_OBJECT(type)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à consulter. * +* closure = adresse non utilisée ici. * +* * +* Description : Retourne le souvenir d'une correspondance racine. * +* * +* Retour : Dernière correspondance établie ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_get_root_record(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GMatchRecord *record; /* Correspondance à convertir */ + +#define KAITAI_SCOPE_ROOT_RECORD_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + root_record, py_kaitai_scope, \ + "Provide the first record for a parsed content.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.kaitai.MatchRecord" \ + " instance or *None*." \ +) + + locals = (py_kaitai_scope_t *)self; + + record = get_root_record(locals->native); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à consulter. * +* closure = adresse non utilisée ici. * +* * +* Description : Retourne le souvenir de la correspondance parente effectuée. * +* * +* Retour : Dernière correspondance établie ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_get_parent_record(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GMatchRecord *record; /* Correspondance à convertir */ + +#define KAITAI_SCOPE_PARENT_RECORD_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + parent_record, py_kaitai_scope, \ + "Provide the current parent record for a parsed content.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.kaitai.MatchRecord" \ + " instance or *None*." \ +) + + locals = (py_kaitai_scope_t *)self; + + record = get_parent_record(locals->native); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à consulter. * +* closure = adresse non utilisée ici. * +* * +* Description : Retourne le souvenir de la dernière correspondance effectuée.* +* * +* Retour : Dernière correspondance établie ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_get_last_record(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GMatchRecord *record; /* Correspondance à convertir */ + +#define KAITAI_SCOPE_LAST_RECORD_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + last_record, py_kaitai_scope, \ + "Provide the last createdrecord for a parsed content.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.kaitai.MatchRecord" \ + " instance or *None*." \ +) + + locals = (py_kaitai_scope_t *)self; + + record = get_last_record(locals->native); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_scope_type(void) +{ + static PyMethodDef py_kaitai_scope_methods[] = { + KAITAI_SCOPE_REMEMBER_LAST_RECORD_METHOD, + KAITAI_SCOPE_FIND_SUB_TYPE_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_scope_getseters[] = { + KAITAI_SCOPE_ROOT_RECORD_ATTRIB, + KAITAI_SCOPE_PARENT_RECORD_ATTRIB, + KAITAI_SCOPE_LAST_RECORD_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_scope_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiScope", + .tp_basicsize = sizeof(py_kaitai_scope_t), + + .tp_dealloc = (destructor)py_kaitai_scope_dealloc, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_SCOPE_DOC, + + .tp_methods = py_kaitai_scope_methods, + .tp_getset = py_kaitai_scope_getseters, + + .tp_init = (initproc)py_kaitai_scope_init, + .tp_new = PyType_GenericNew, + + }; + + return &py_kaitai_scope_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_scope_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PackedBuffer' */ + PyObject *module; /* Module à recompléter */ + + type = get_python_kaitai_scope_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + if (PyType_Ready(type) != 0) + return false; + + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + if (!register_python_module_object(module, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = structure interne à copier en objet Python. * +* * +* Description : Convertit une structure 'kaitai_scope_t' en objet Python. * +* * +* Retour : Object Python résultant de la conversion opérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *build_from_internal_kaitai_scope(const kaitai_scope_t *locals) +{ + PyObject *result; /* Instance à retourner */ + PyTypeObject *type; /* Type à instancier */ + + type = get_python_kaitai_scope_type(); + + result = PyObject_CallObject((PyObject *)type, NULL); + + copy_record_scope(((py_kaitai_scope_t *)result)->native, locals); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en environnement local pour Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_scope(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_scope_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai scope"); + break; + + case 1: + *((kaitai_scope_t **)dst) = ((py_kaitai_scope_t *)arg)->native; + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/scope.h b/plugins/kaitai/python/scope.h new file mode 100644 index 0000000..9353b06 --- /dev/null +++ b/plugins/kaitai/python/scope.h @@ -0,0 +1,51 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/scope.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_SCOPE_H +#define _PLUGINS_KAITAI_PYTHON_SCOPE_H + + +#include <Python.h> +#include <stdbool.h> + + +#include "../scope.h" + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_scope_type(void); + +/* Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. */ +bool ensure_python_kaitai_scope_is_registered(void); + +/* Convertit une structure 'kaitai_scope_t' en objet Python. */ +PyObject *build_from_internal_kaitai_scope(const kaitai_scope_t *); + +/* Tente de convertir en environnement local pour Kaitai. */ +int convert_to_kaitai_scope(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_SCOPE_H */ diff --git a/plugins/kaitai/python/stream.c b/plugins/kaitai/python/stream.c new file mode 100644 index 0000000..985e3c3 --- /dev/null +++ b/plugins/kaitai/python/stream.c @@ -0,0 +1,278 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * stream.h - équivalent Python du fichier "plugins/kaitai/stream.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "stream.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> + + +#include "../stream-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_stream, G_TYPE_KAITAI_STREAM); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_stream_init(PyObject *, PyObject *, PyObject *); + +/* Détermine si la fin des données a été atteinte. */ +static PyObject *py_kaitai_stream_get_eof(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_stream_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GBinContent *content; /* Contenu binaire manipulé */ + vmpa2t *pos; /* Tête de lecture courante */ + int ret; /* Bilan de lecture des args. */ + GKaitaiStream *stream; /* Création GLib à transmettre */ + +#define KAITAI_STREAM_DOC \ + "KaitaiStream collects all the information useful for the processing of" \ + " binary data." \ + "\n" \ + "Instances can be created using following constructor:\n" \ + "\n" \ + " KaitaiStream(content, pos)" \ + "\n" \ + "Where *content* is a pychrysalide.analysis.BinContent instance providing" \ + " the processed data and *pos* defines the current reading location, as a" \ + " pychrysalide.arch.vmpa value." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &content, convert_any_to_vmpa, &pos); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + stream = G_KAITAI_STREAM(pygobject_get(self)); + + if (!g_kaitai_stream_create(stream, content, pos)) + { + clean_vmpa_arg(pos); + + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream.")); + return -1; + + } + + clean_vmpa_arg(pos); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Détermine si la fin des données a été atteinte. * +* * +* Retour : True si la tête de lecture est en position finale, ou False. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_stream_get_eof(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiStream *stream; /* Version native dyu flux */ + bool status; /* Etat de la position courante*/ + +#define KAITAI_STREAM_EOF_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + eof, py_kaitai_stream, \ + "Boolean value stating if the end of the stream" \ + " has been reached or not." \ +) + + stream = G_KAITAI_STREAM(pygobject_get(self)); + + status = g_kaitai_stream_has_reached_eof(stream); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_stream_type(void) +{ + static PyMethodDef py_kaitai_stream_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_stream_getseters[] = { + KAITAI_STREAM_EOF_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_stream_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiStream", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_STREAM_DOC, + + .tp_methods = py_kaitai_stream_methods, + .tp_getset = py_kaitai_stream_getseters, + + .tp_init = py_kaitai_stream_init, + .tp_new = py_kaitai_stream_new, + + }; + + return &py_kaitai_stream_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiStream.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_stream_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiStream' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_stream_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_STREAM, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en flux de données pour Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_stream(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_stream_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai stream"); + break; + + case 1: + *((GKaitaiStream **)dst) = G_KAITAI_STREAM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/stream.h b/plugins/kaitai/python/stream.h new file mode 100644 index 0000000..4f61358 --- /dev/null +++ b/plugins/kaitai/python/stream.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * stream.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/stream.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_STREAM_H +#define _PLUGINS_KAITAI_PYTHON_STREAM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_stream_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiStream'. */ +bool ensure_python_kaitai_stream_is_registered(void); + +/* Tente de convertir en flux de données pour Kaitai. */ +int convert_to_kaitai_stream(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_STREAM_H */ |