/*
 * Copyright © 2023 Contrast Security, Inc.
 * See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
 */
/* THIS FILE WAS AUTOMATICALLY GENERATED BY HOOKSPY */
/* Python requires its own header to always be included first */
#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include <contrast/assess/patches.h>
#include <contrast/assess/propagate.h>
#include <contrast/assess/scope.h>
#include <contrast/assess/utils.h>

typedef PyObject *(*fastcall_func)(PyObject *, PyObject *const *, Py_ssize_t);
typedef PyObject *(*fastcall_kwargs_func)(
    PyObject *, PyObject *const *, Py_ssize_t, PyObject *);

#define UNICODE_ENCODE_OFFSET 0
#define UNICODE_REPLACE_OFFSET 1
#define UNICODE_SPLIT_OFFSET 2
#define UNICODE_RSPLIT_OFFSET 3
#define UNICODE_JOIN_OFFSET 4
#define UNICODE_CAPITALIZE_OFFSET 5
#define UNICODE_CASEFOLD_OFFSET 6
#define UNICODE_TITLE_OFFSET 7
#define UNICODE_CENTER_OFFSET 8
#define UNICODE_EXPANDTABS_OFFSET 10
#define UNICODE_PARTITION_OFFSET 12
#define UNICODE_LJUST_OFFSET 14
#define UNICODE_LOWER_OFFSET 15
#define UNICODE_LSTRIP_OFFSET 16
#define UNICODE_RJUST_OFFSET 19
#define UNICODE_RSTRIP_OFFSET 20
#define UNICODE_RPARTITION_OFFSET 21
#define UNICODE_SPLITLINES_OFFSET 22
#define UNICODE_STRIP_OFFSET 23
#define UNICODE_SWAPCASE_OFFSET 24
#define UNICODE_TRANSLATE_OFFSET 25
#define UNICODE_UPPER_OFFSET 26
#define UNICODE_ZFILL_OFFSET 40
#define UNICODE_FORMATMAP_OFFSET 42

ternaryfunc unicode_encode_orig;
binaryfunc unicode_replace_orig;
ternaryfunc unicode_split_orig;
ternaryfunc unicode_rsplit_orig;
binaryfunc unicode_join_orig;
unaryfunc unicode_capitalize_orig;
unaryfunc unicode_casefold_orig;
unaryfunc unicode_title_orig;
binaryfunc unicode_center_orig;
ternaryfunc unicode_expandtabs_orig;
binaryfunc unicode_partition_orig;
binaryfunc unicode_ljust_orig;
unaryfunc unicode_lower_orig;
binaryfunc unicode_lstrip_orig;
binaryfunc unicode_rjust_orig;
binaryfunc unicode_rstrip_orig;
binaryfunc unicode_rpartition_orig;
ternaryfunc unicode_splitlines_orig;
binaryfunc unicode_strip_orig;
unaryfunc unicode_swapcase_orig;
binaryfunc unicode_translate_orig;
unaryfunc unicode_upper_orig;
binaryfunc unicode_zfill_orig;
binaryfunc unicode_formatmap_orig;

HOOK_TERNARYFUNC(unicode_encode);
HOOK_BINARYFUNC(unicode_replace);
HOOK_TERNARYFUNC(unicode_split);
HOOK_TERNARYFUNC(unicode_rsplit);
PyObject *unicode_join_new(PyObject *self, PyObject *args) {
    PyObject *list = PySequence_List(args);

    /* If this fails for any reason, just call the original function and get
     * out of here.
     */
    if (list == NULL) {
        PyErr_Clear();
        return unicode_join_orig((PyObject *)self, args);
    }

    /* In Py36+ we also hook an internal function that is called by this
     * function in order to propagate fstring formatting. We still want to have
     * a separate hook for join so that the events are reported differently.
     * This means that we need to go into scope when calling the original
     * function here so that we don't propagate twice.
     */
    enter_propagation_scope();
    PyObject *result = unicode_join_orig((PyObject *)self, list);
    exit_propagation_scope();

    PyObject *prop_args = PyTuple_Pack(1, list);

    if (prop_args == NULL || result == NULL)
        goto cleanup_and_exit;

    call_string_propagator(
        "propagate_unicode_join", (PyObject *)self, result, prop_args, NULL);

cleanup_and_exit:
    Py_XDECREF(list);
    Py_XDECREF(prop_args);
    return result;
}

HOOK_UNARYFUNC(unicode_capitalize);
HOOK_UNARYFUNC(unicode_casefold);
HOOK_UNARYFUNC(unicode_title);
HOOK_BINARYFUNC(unicode_center);
HOOK_TERNARYFUNC(unicode_expandtabs);
HOOK_BINARYFUNC(unicode_partition);
HOOK_BINARYFUNC(unicode_ljust);
HOOK_UNARYFUNC(unicode_lower);
HOOK_BINARYFUNC(unicode_lstrip);
HOOK_BINARYFUNC(unicode_rjust);
HOOK_BINARYFUNC(unicode_rstrip);
HOOK_BINARYFUNC(unicode_rpartition);
HOOK_TERNARYFUNC(unicode_splitlines);
HOOK_BINARYFUNC(unicode_strip);
HOOK_UNARYFUNC(unicode_swapcase);
HOOK_BINARYFUNC(unicode_translate);
HOOK_UNARYFUNC(unicode_upper);
HOOK_BINARYFUNC(unicode_zfill);
PyObject *unicode_formatmap_new(PyObject *self, PyObject *args) {
    PyObject *result = unicode_formatmap_orig(self, args);

    if (result == NULL)
        return result;

    call_string_propagator("propagate_unicode_formatmap", self, result, NULL, args);

    return result;
}

CREATE_HOOK_METHOD(PyUnicode_Type, unicode_encode, 0)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_replace, 1)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_split, 2)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_rsplit, 3)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_join, 4)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_capitalize, 5)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_casefold, 6)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_title, 7)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_center, 8)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_expandtabs, 10)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_partition, 12)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_ljust, 14)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_lower, 15)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_lstrip, 16)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_rjust, 19)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_rstrip, 20)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_rpartition, 21)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_splitlines, 22)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_strip, 23)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_swapcase, 24)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_translate, 25)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_upper, 26)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_zfill, 40)
CREATE_HOOK_METHOD(PyUnicode_Type, unicode_formatmap, 42)

static PyMethodDef methods[] = {
    {"apply_encode_hook",
     apply_unicode_encode_hook,
     METH_O,
     "Enable unicode.encode hook"},
    {"apply_replace_hook",
     apply_unicode_replace_hook,
     METH_O,
     "Enable unicode.replace hook"},
    {"apply_split_hook", apply_unicode_split_hook, METH_O, "Enable unicode.split hook"},
    {"apply_rsplit_hook",
     apply_unicode_rsplit_hook,
     METH_O,
     "Enable unicode.rsplit hook"},
    {"apply_join_hook", apply_unicode_join_hook, METH_O, "Enable unicode.join hook"},
    {"apply_capitalize_hook",
     apply_unicode_capitalize_hook,
     METH_O,
     "Enable unicode.capitalize hook"},
    {"apply_casefold_hook",
     apply_unicode_casefold_hook,
     METH_O,
     "Enable unicode.casefold hook"},
    {"apply_title_hook", apply_unicode_title_hook, METH_O, "Enable unicode.title hook"},
    {"apply_center_hook",
     apply_unicode_center_hook,
     METH_O,
     "Enable unicode.center hook"},
    {"apply_expandtabs_hook",
     apply_unicode_expandtabs_hook,
     METH_O,
     "Enable unicode.expandtabs hook"},
    {"apply_partition_hook",
     apply_unicode_partition_hook,
     METH_O,
     "Enable unicode.partition hook"},
    {"apply_ljust_hook", apply_unicode_ljust_hook, METH_O, "Enable unicode.ljust hook"},
    {"apply_lower_hook", apply_unicode_lower_hook, METH_O, "Enable unicode.lower hook"},
    {"apply_lstrip_hook",
     apply_unicode_lstrip_hook,
     METH_O,
     "Enable unicode.lstrip hook"},
    {"apply_rjust_hook", apply_unicode_rjust_hook, METH_O, "Enable unicode.rjust hook"},
    {"apply_rstrip_hook",
     apply_unicode_rstrip_hook,
     METH_O,
     "Enable unicode.rstrip hook"},
    {"apply_rpartition_hook",
     apply_unicode_rpartition_hook,
     METH_O,
     "Enable unicode.rpartition hook"},
    {"apply_splitlines_hook",
     apply_unicode_splitlines_hook,
     METH_O,
     "Enable unicode.splitlines hook"},
    {"apply_strip_hook", apply_unicode_strip_hook, METH_O, "Enable unicode.strip hook"},
    {"apply_swapcase_hook",
     apply_unicode_swapcase_hook,
     METH_O,
     "Enable unicode.swapcase hook"},
    {"apply_translate_hook",
     apply_unicode_translate_hook,
     METH_O,
     "Enable unicode.translate hook"},
    {"apply_upper_hook", apply_unicode_upper_hook, METH_O, "Enable unicode.upper hook"},
    {"apply_zfill_hook", apply_unicode_zfill_hook, METH_O, "Enable unicode.zfill hook"},
    {"apply_formatmap_hook",
     apply_unicode_formatmap_hook,
     METH_O,
     "Enable unicode.formatmap hook"},
    {NULL, NULL, 0, NULL},
};

static struct PyModuleDef unicode_module_def = {
    PyModuleDef_HEAD_INIT,
    "unicode_hooks",
    "methods for hooking unicode methods",
    -1,
    methods,
    NULL,
    NULL,
    NULL,
    NULL};

PyObject *create_unicode_hook_module(PyObject *self, PyObject *arg) {
    return PyModule_Create(&unicode_module_def);
}
