/*
 * 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 BYTES_DECODE_OFFSET 4
#define BYTES_REPLACE_OFFSET 24
#define BYTES_SPLIT_OFFSET 31
#define BYTES_RSPLIT_OFFSET 29
#define BYTES_JOIN_OFFSET 18
#define BYTES_CAPITALIZE_OFFSET 1
#define BYTES_TITLE_OFFSET 36
#define BYTES_CENTER_OFFSET 2
#define BYTES_EXPANDTABS_OFFSET 6
#define BYTES_PARTITION_OFFSET 23
#define BYTES_LJUST_OFFSET 19
#define BYTES_LOWER_OFFSET 20
#define BYTES_LSTRIP_OFFSET 21
#define BYTES_RJUST_OFFSET 27
#define BYTES_RSTRIP_OFFSET 30
#define BYTES_RPARTITION_OFFSET 28
#define BYTES_SPLITLINES_OFFSET 32
#define BYTES_STRIP_OFFSET 34
#define BYTES_SWAPCASE_OFFSET 35
#define BYTES_TRANSLATE_OFFSET 37
#define BYTES_UPPER_OFFSET 38
#define BYTES_ZFILL_OFFSET 39

ternaryfunc bytes_decode_orig;
binaryfunc bytes_replace_orig;
ternaryfunc bytes_split_orig;
ternaryfunc bytes_rsplit_orig;
binaryfunc bytes_join_orig;
unaryfunc bytes_capitalize_orig;
unaryfunc bytes_title_orig;
binaryfunc bytes_center_orig;
ternaryfunc bytes_expandtabs_orig;
binaryfunc bytes_partition_orig;
binaryfunc bytes_ljust_orig;
unaryfunc bytes_lower_orig;
binaryfunc bytes_lstrip_orig;
binaryfunc bytes_rjust_orig;
binaryfunc bytes_rstrip_orig;
binaryfunc bytes_rpartition_orig;
ternaryfunc bytes_splitlines_orig;
binaryfunc bytes_strip_orig;
unaryfunc bytes_swapcase_orig;
binaryfunc bytes_translate_orig;
unaryfunc bytes_upper_orig;
binaryfunc bytes_zfill_orig;

HOOK_TERNARYFUNC(bytes_decode);
HOOK_BINARYFUNC(bytes_replace);
HOOK_TERNARYFUNC(bytes_split);
HOOK_TERNARYFUNC(bytes_rsplit);
PyObject *bytes_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 bytes_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 = bytes_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_bytes_join", (PyObject *)self, result, prop_args, NULL);

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

HOOK_UNARYFUNC(bytes_capitalize);
HOOK_UNARYFUNC(bytes_title);
HOOK_BINARYFUNC(bytes_center);
HOOK_TERNARYFUNC(bytes_expandtabs);
HOOK_BINARYFUNC(bytes_partition);
HOOK_BINARYFUNC(bytes_ljust);
HOOK_UNARYFUNC(bytes_lower);
HOOK_BINARYFUNC(bytes_lstrip);
HOOK_BINARYFUNC(bytes_rjust);
HOOK_BINARYFUNC(bytes_rstrip);
HOOK_BINARYFUNC(bytes_rpartition);
HOOK_TERNARYFUNC(bytes_splitlines);
HOOK_BINARYFUNC(bytes_strip);
HOOK_UNARYFUNC(bytes_swapcase);
HOOK_BINARYFUNC(bytes_translate);
HOOK_UNARYFUNC(bytes_upper);
HOOK_BINARYFUNC(bytes_zfill);

CREATE_HOOK_METHOD(PyBytes_Type, bytes_decode, 4)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_replace, 24)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_split, 31)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_rsplit, 29)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_join, 18)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_capitalize, 1)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_title, 36)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_center, 2)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_expandtabs, 6)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_partition, 23)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_ljust, 19)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_lower, 20)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_lstrip, 21)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_rjust, 27)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_rstrip, 30)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_rpartition, 28)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_splitlines, 32)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_strip, 34)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_swapcase, 35)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_translate, 37)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_upper, 38)
CREATE_HOOK_METHOD(PyBytes_Type, bytes_zfill, 39)

static PyMethodDef methods[] = {
    {"apply_decode_hook", apply_bytes_decode_hook, METH_O, "Enable bytes.decode hook"},
    {"apply_replace_hook",
     apply_bytes_replace_hook,
     METH_O,
     "Enable bytes.replace hook"},
    {"apply_split_hook", apply_bytes_split_hook, METH_O, "Enable bytes.split hook"},
    {"apply_rsplit_hook", apply_bytes_rsplit_hook, METH_O, "Enable bytes.rsplit hook"},
    {"apply_join_hook", apply_bytes_join_hook, METH_O, "Enable bytes.join hook"},
    {"apply_capitalize_hook",
     apply_bytes_capitalize_hook,
     METH_O,
     "Enable bytes.capitalize hook"},
    {"apply_title_hook", apply_bytes_title_hook, METH_O, "Enable bytes.title hook"},
    {"apply_center_hook", apply_bytes_center_hook, METH_O, "Enable bytes.center hook"},
    {"apply_expandtabs_hook",
     apply_bytes_expandtabs_hook,
     METH_O,
     "Enable bytes.expandtabs hook"},
    {"apply_partition_hook",
     apply_bytes_partition_hook,
     METH_O,
     "Enable bytes.partition hook"},
    {"apply_ljust_hook", apply_bytes_ljust_hook, METH_O, "Enable bytes.ljust hook"},
    {"apply_lower_hook", apply_bytes_lower_hook, METH_O, "Enable bytes.lower hook"},
    {"apply_lstrip_hook", apply_bytes_lstrip_hook, METH_O, "Enable bytes.lstrip hook"},
    {"apply_rjust_hook", apply_bytes_rjust_hook, METH_O, "Enable bytes.rjust hook"},
    {"apply_rstrip_hook", apply_bytes_rstrip_hook, METH_O, "Enable bytes.rstrip hook"},
    {"apply_rpartition_hook",
     apply_bytes_rpartition_hook,
     METH_O,
     "Enable bytes.rpartition hook"},
    {"apply_splitlines_hook",
     apply_bytes_splitlines_hook,
     METH_O,
     "Enable bytes.splitlines hook"},
    {"apply_strip_hook", apply_bytes_strip_hook, METH_O, "Enable bytes.strip hook"},
    {"apply_swapcase_hook",
     apply_bytes_swapcase_hook,
     METH_O,
     "Enable bytes.swapcase hook"},
    {"apply_translate_hook",
     apply_bytes_translate_hook,
     METH_O,
     "Enable bytes.translate hook"},
    {"apply_upper_hook", apply_bytes_upper_hook, METH_O, "Enable bytes.upper hook"},
    {"apply_zfill_hook", apply_bytes_zfill_hook, METH_O, "Enable bytes.zfill hook"},
    {NULL, NULL, 0, NULL},
};

static struct PyModuleDef bytes_module_def = {
    PyModuleDef_HEAD_INIT,
    "bytes_hooks",
    "methods for hooking bytes methods",
    -1,
    methods,
    NULL,
    NULL,
    NULL,
    NULL};

PyObject *create_bytes_hook_module(PyObject *self, PyObject *arg) {
    return PyModule_Create(&bytes_module_def);
}
