ImHex/source/helpers/loader_script_handler.cpp

230 lines
7.7 KiB
C++
Raw Normal View History

2020-12-01 01:21:40 +00:00
#include "helpers/loader_script_handler.hpp"
#include <hex/helpers/utils.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/file.hpp>
2021-08-29 20:15:18 +00:00
#include <hex/views/view.hpp>
#include <hex/providers/provider.hpp>
2020-12-01 01:21:40 +00:00
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>
2020-12-01 01:21:40 +00:00
#include <cstring>
#include <filesystem>
using namespace std::literals::string_literals;
2020-12-01 01:21:40 +00:00
namespace hex {
PyObject* LoaderScript::Py_getFilePath(PyObject *self, PyObject *args) {
return PyUnicode_FromString(LoaderScript::s_filePath.c_str());
}
PyObject* LoaderScript::Py_addPatch(PyObject *self, PyObject *args) {
u64 address;
u8 *patches;
Py_ssize_t count;
if (!PyArg_ParseTuple(args, "K|y#", &address, &patches, &count)) {
PyErr_BadArgument();
return nullptr;
}
if (patches == nullptr || count == 0) {
PyErr_SetString(PyExc_TypeError, "Invalid patch provided");
return nullptr;
}
if (address >= LoaderScript::s_dataProvider->getActualSize()) {
PyErr_SetString(PyExc_IndexError, "address out of range");
return nullptr;
}
LoaderScript::s_dataProvider->write(address, patches, count);
Py_RETURN_NONE;
}
PyObject* LoaderScript::Py_addBookmark(PyObject *self, PyObject *args) {
2021-01-20 19:16:24 +00:00
u64 address;
size_t size;
2020-12-01 01:21:40 +00:00
char *name = nullptr;
char *comment = nullptr;
2021-01-20 19:16:24 +00:00
if (!PyArg_ParseTuple(args, "K|n|s|s", &address, &size, &name, &comment)) {
2020-12-01 01:21:40 +00:00
PyErr_BadArgument();
return nullptr;
}
if (name == nullptr || comment == nullptr) {
PyErr_SetString(PyExc_IndexError, "address out of range");
return nullptr;
}
2021-01-20 19:16:24 +00:00
ImHexApi::Bookmarks::add(address, size, name, comment);
2020-12-01 01:21:40 +00:00
Py_RETURN_NONE;
}
static PyObject* createStructureType(std::string keyword, PyObject *args) {
auto type = PyTuple_GetItem(args, 0);
if (type == nullptr) {
PyErr_BadArgument();
return nullptr;
}
auto instance = PyObject_CallObject(type, nullptr);
if (instance == nullptr) {
PyErr_BadArgument();
return nullptr;
}
2021-03-31 20:54:43 +00:00
ON_SCOPE_EXIT { Py_DECREF(instance); };
if (instance->ob_type->tp_base == nullptr || instance->ob_type->tp_base->tp_name != "ImHexType"s) {
PyErr_SetString(PyExc_TypeError, "class type must extend from ImHexType");
return nullptr;
}
auto dict = instance->ob_type->tp_dict;
if (dict == nullptr) {
PyErr_BadArgument();
return nullptr;
}
auto annotations = PyDict_GetItemString(dict, "__annotations__");
if (annotations == nullptr) {
PyErr_BadArgument();
return nullptr;
}
auto list = PyDict_Items(annotations);
if (list == nullptr) {
PyErr_BadArgument();
return nullptr;
}
2021-03-31 20:54:43 +00:00
ON_SCOPE_EXIT { Py_DECREF(list); };
std::string code = keyword + " " + instance->ob_type->tp_name + " {\n";
for (u16 i = 0; i < PyList_Size(list); i++) {
auto item = PyList_GetItem(list, i);
auto memberName = PyUnicode_AsUTF8(PyTuple_GetItem(item, 0));
auto memberType = PyTuple_GetItem(item, 1);
if (memberType == nullptr) {
PyErr_SetString(PyExc_TypeError, "member needs to have a annotation extending from ImHexType");
return nullptr;
}
// Array already is an object
if (memberType->ob_type->tp_name == "array"s) {
auto arrayType = PyObject_GetAttrString(memberType, "array_type");
if (arrayType == nullptr) {
PyErr_BadArgument();
return nullptr;
}
code += " "s + arrayType->ob_type->tp_name + " " + memberName;
auto arraySize = PyObject_GetAttrString(memberType, "size");
if (arraySize == nullptr) {
PyErr_BadArgument();
return nullptr;
}
if (PyUnicode_Check(arraySize))
code += "["s + PyUnicode_AsUTF8(arraySize) + "];\n";
else if (PyLong_Check(arraySize))
code += "["s + std::to_string(PyLong_AsLong(arraySize)) + "];\n";
else {
PyErr_SetString(PyExc_TypeError, "invalid array size type. Expected string or int");
return nullptr;
}
} else {
auto memberTypeInstance = PyObject_CallObject(memberType, nullptr);
if (memberTypeInstance == nullptr || memberTypeInstance->ob_type->tp_base == nullptr || memberTypeInstance->ob_type->tp_base->tp_name != "ImHexType"s) {
PyErr_SetString(PyExc_TypeError, "member needs to have a annotation extending from ImHexType");
if (memberTypeInstance != nullptr)
Py_DECREF(memberTypeInstance);
return nullptr;
}
code += " "s + memberTypeInstance->ob_type->tp_name + " "s + memberName + ";\n";
Py_DECREF(memberTypeInstance);
}
}
code += "};\n";
EventManager::post<RequestAppendPatternLanguageCode>(code);
Py_RETURN_NONE;
}
PyObject* LoaderScript::Py_addStruct(PyObject *self, PyObject *args) {
return createStructureType("struct", args);
}
PyObject* LoaderScript::Py_addUnion(PyObject *self, PyObject *args) {
return createStructureType("union", args);
}
bool LoaderScript::processFile(const std::string &scriptPath) {
Py_SetProgramName(Py_DecodeLocale((SharedData::mainArgv)[0], nullptr));
2020-12-01 01:21:40 +00:00
sys/build: Properly support per-system metadata file paths (#181) * sys: Move away from metadata paths next to executable in the application Build system doesn't properly install / pack stuff yet * build: Updated README to contain better install instructions * sys: Search for imhex resource files in ~/Application Support * sys: MAX_PATH -> PATH_MAX * sys: Seach for imhex resource files in Application Support using NSFileManager (#180) * sys: Allow for multiple file search paths Also use install prefix instead of just /usr on Linux * build: Fixed IMHEX_INSTALL_PREFIX macro definition * build: Fix duplicate switch entry on Linux * docs: Updated readme to properly reflect new paths and dependencies * sys: Install files in their proper paths on linux (#183) * Install files in their proper paths on linux * Only create user directories * Follow the XDG specification on linux XDG specification specifies how to find config and data directories on linux systems. Specifically, it says this: - Data should be written to $XDG_DATA_HOME - Config should be written to $XDG_CONFIG_HOME - Data should be read from $XDG_DATA_HOME:$XDG_DATA_DIRS - Config should be read from $XDG_CONFIG_HOME:$XDG_CONFIG_DIRS The default values are this: - XDG_DATA_HOME: $HOME/.local/share - XDG_CONFIG_HOME: $HOME/.config - XDG_DATA_DIRS: /usr/share:/usr/local/share - XDG_CONFIG_DIRS: /etc/xdg Platforms with non-standard filesystems (like NixOS) will correctly set up those environment variables, allowing softwares to work unmodified. In order to make integration as simple as possible, we use a simple header-only dependency called XDGPP which does all the hard work for us to find the default directories. * Look for plugins in all Plugin Paths If the plugin folder was missing from one of the PluginPaths, we would immediately stop loading plugins. We now keep looking even if one of the path is missing. Co-authored-by: Nichole Mattera <me@nicholemattera.com> Co-authored-by: Robin Lambertz <unfiltered@roblab.la>
2021-03-01 07:56:49 +00:00
for (const auto &dir : hex::getPath(ImHexPath::Python)) {
if (std::filesystem::exists(std::filesystem::path(dir + "/lib/python" PYTHON_VERSION_MAJOR_MINOR))) {
Py_SetPythonHome(Py_DecodeLocale(dir.c_str(), nullptr));
break;
}
}
PyImport_AppendInittab("_imhex", []() -> PyObject* {
2020-12-01 01:21:40 +00:00
static PyMethodDef ImHexMethods[] = {
{ "get_file_path", &LoaderScript::Py_getFilePath, METH_NOARGS, "Returns the path of the file being loaded." },
{ "patch", &LoaderScript::Py_addPatch, METH_VARARGS, "Patches a region of memory" },
{ "add_bookmark", &LoaderScript::Py_addBookmark, METH_VARARGS, "Adds a bookmark" },
{ "add_struct", &LoaderScript::Py_addStruct, METH_VARARGS, "Adds a struct" },
{ "add_union", &LoaderScript::Py_addUnion, METH_VARARGS, "Adds a union" },
{ nullptr, nullptr, 0, nullptr }
2020-12-01 01:21:40 +00:00
};
static PyModuleDef ImHexModule = {
PyModuleDef_HEAD_INIT, "imhex", nullptr, -1, ImHexMethods, nullptr, nullptr, nullptr, nullptr
};
auto module = PyModule_Create(&ImHexModule);
if (module == nullptr)
return nullptr;
return module;
2020-12-01 01:21:40 +00:00
});
Py_Initialize();
{
auto sysPath = PySys_GetObject("path");
auto path = PyUnicode_FromString("lib");
PyList_Insert(sysPath, 0, path);
}
File scriptFile(scriptPath, File::Mode::Read);
PyRun_SimpleFile(scriptFile.getHandle(), scriptPath.c_str());
2020-12-01 01:21:40 +00:00
Py_Finalize();
return true;
}
}