/* Chrysalide - Outil d'analyse de fichiers binaires * strbuilder.c - équivalent Python du fichier "glibext/strbuilder.c" * * Copyright (C) 2021 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 "strbuilder.h" #include #include #include #include "../access.h" #include "../helpers.h" /* Procède à l'initialisation de l'interface d'exportation. */ static void py_string_builder_interface_init(GStringBuilderInterface *, gpointer *); /* Exporte une chaîne de caractères à partir d'un objet. */ bool py_string_builder_to_string_wrapper(const GStringBuilder *, unsigned int, sized_binary_t *); /* Exporte une chaîne de caractères à partir d'un objet. */ static PyObject *py_string_builder_to_string(PyObject *, PyObject *); /* Fournit une représentation de l'objet exportable. */ static PyObject *py_string_builder_str(PyObject *); /****************************************************************************** * * * Paramètres : iface = interface GLib à initialiser. * * unused = adresse non utilisée ici. * * * * Description : Procède à l'initialisation de l'interface d'exportation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_string_builder_interface_init(GStringBuilderInterface *iface, gpointer *unused) { #define STRING_BUILDER_DOC \ "The StringBuilder class defines a interface for native objects aiming" \ " at providing a string representation of themselves.\n" \ "\n" \ "A typical class declaration for a new implementation looks like:\n" \ "\n" \ " class NewImplem(GObject.Object, StringBuilder):\n" \ " ...\n" \ "\n" \ "The following method has to be defined for new implementations:\n" \ "* pychrysalide.glibext.StringBuilder._to_string().\n" iface->to_string = py_string_builder_to_string_wrapper; } /****************************************************************************** * * * Paramètres : builder = objet dont l'instance est exportable. * * flags = éventuelles indications pour l'opération. * * out = chaîne de caractères mise en place. [OUT] * * * * Description : Exporte une chaîne de caractères à partir d'un objet. * * * * Retour : Bilan de l'opération. * * * * Remarques : La sortie out est à nettoyer avec exit_sized_binary() après * * usage. * * * ******************************************************************************/ bool py_string_builder_to_string_wrapper(const GStringBuilder *builder, unsigned int flags, sized_binary_t *out) { bool result; /* Bilan à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Bilan de consultation */ const char *utf8; /* Chaîne UTF-8 portée */ Py_ssize_t size; /* Taille de ces données */ #define STRING_BUILDER_TO_STRING_WRAPPER PYTHON_WRAPPER_DEF \ ( \ _to_string, "$self, /, flags=0", \ METH_VARARGS, \ "Abstract method providing a string representation for the" \ " object which is used as the default implementation of the" \ " __repr__() method.\n" \ "\n" \ "The optional *flags* argument define hints for the operation" \ " (for instance the Intel or AT&T flavor for x86 assembly).\n" \ "\n" \ "The result has to be a string or *None* in case of error." \ ) result = false; gstate = PyGILState_Ensure(); pyobj = pygobject_new(G_OBJECT(builder)); if (has_python_method(pyobj, "_to_string")) { args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(flags)); pyret = run_python_method(pyobj, "_to_string", args); if (pyret != NULL && pyret != Py_None) { if (PyUnicode_Check(pyret)) { utf8 = PyUnicode_AsUTF8AndSize(pyret, &size); if (utf8 != NULL) { assert(size >= 0); add_to_sized_binary(out, utf8, size); result = true; } } } Py_XDECREF(pyret); Py_DECREF(args); } Py_DECREF(pyobj); PyGILState_Release(gstate); return result; } /****************************************************************************** * * * Paramètres : self = objet manipulé ici. * * args = adresse non utilisée ici. * * * * Description : Exporte une chaîne de caractères à partir d'un objet. * * * * Retour : Présentation de l'élément construite ou None. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_string_builder_to_string(PyObject *self, PyObject *args) { PyObject *result; /* Emplacement à retourner */ unsigned int flags; /* Eventuelles indications */ int ret; /* Bilan de lecture des args. */ GStringBuilder *builder; /* Mécanismes natifs */ sized_binary_t out; /* Description construite */ bool status; /* Bilan de l'opération */ #define STRING_BUILDER_TO_STRING_METHOD PYTHON_METHOD_DEF \ ( \ to_string, "$self, /, flags=0", \ METH_VARARGS, py_string_builder, \ "Provide a string representation for the object which is used" \ " as the default implementation of the __repr__() method.\n" \ "\n" \ "\n" \ "The optional *flags* argument define hints for the operation" \ " (for instance the Intel or AT&T flavor for x86 assembly).\n" \ "\n" \ "The result is a string or *None* in case of error." \ ) flags = 0; ret = PyArg_ParseTuple(args, "|I", &flags); if (!ret) return NULL; builder = G_STRING_BUILDER(pygobject_get(self)); init_sized_binary(&out); status = g_string_builder_to_string(builder, flags, &out); if (status) result = PyUnicode_FromStringAndSize(out.data, out.size); else { result = Py_None; Py_INCREF(result); } exit_sized_binary(&out); return result; } /****************************************************************************** * * * Paramètres : self = objet manipulé ici. * * * * Description : Fournit une représentation de l'objet exportable. * * * * Retour : Présentation de l'élément construite ou None. * * * * Remarques : - * * * ******************************************************************************/ PyObject *py_string_builder_str(PyObject *self) { PyObject *result; /* Emplacement à retourner */ GStringBuilder *builder; /* Mécanismes natifs */ sized_binary_t out; /* Description construite */ bool status; /* Bilan de l'opération */ builder = G_STRING_BUILDER(pygobject_get(self)); init_sized_binary(&out); status = g_string_builder_to_string(builder, 0, &out); if (status) result = PyUnicode_FromStringAndSize(out.data, out.size); else { result = Py_None; Py_INCREF(result); } exit_sized_binary(&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_string_builder_type(void) { static PyMethodDef py_string_builder_methods[] = { STRING_BUILDER_TO_STRING_WRAPPER, STRING_BUILDER_TO_STRING_METHOD, { NULL } }; static PyGetSetDef py_string_builder_getseters[] = { { NULL } }; static PyTypeObject py_string_builder_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.glibext.StringBuilder", .tp_basicsize = sizeof(PyObject), .tp_str = py_string_builder_str, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = STRING_BUILDER_DOC, .tp_methods = py_string_builder_methods, .tp_getset = py_string_builder_getseters }; return &py_string_builder_type; } /****************************************************************************** * * * Paramètres : - * * * * Description : Prend en charge l'objet 'pychrysalide.glibext.StringBuilder'.* * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool ensure_python_string_builder_is_registered(void) { PyTypeObject *type; /* Type Python 'StringBuilder' */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ static GInterfaceInfo info = { /* Paramètres d'inscription */ .interface_init = (GInterfaceInitFunc)py_string_builder_interface_init, .interface_finalize = NULL, .interface_data = NULL, }; type = get_python_string_builder_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide.glibext"); dict = PyModule_GetDict(module); if (!register_interface_for_pygobject(dict, G_TYPE_STRING_BUILDER, type, &info)) 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 interface d'exportation en chaîne. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * * Remarques : - * * * ******************************************************************************/ int convert_to_string_builder(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ result = PyObject_IsInstance(arg, (PyObject *)get_python_string_builder_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 string builder"); break; case 1: *((GStringBuilder **)dst) = G_STRING_BUILDER(pygobject_get(arg)); break; default: assert(false); break; } return result; }