diff options
Diffstat (limited to 'plugins/kaitai/python/scope.c')
-rw-r--r-- | plugins/kaitai/python/scope.c | 542 |
1 files changed, 542 insertions, 0 deletions
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; + +} |