Coverage Report

Created: 2025-07-11 06:59

/src/Python-3.8.3/Python/pystrhex.c
Line
Count
Source (jump to first uncovered line)
1
/* bytes to hex implementation */
2
3
#include "Python.h"
4
5
#include "pystrhex.h"
6
7
static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen,
8
                                 const PyObject* sep, int bytes_per_sep_group,
9
                                 const int return_bytes)
10
0
{
11
0
    PyObject *retval;
12
0
    Py_UCS1* retbuf;
13
0
    Py_ssize_t i, j, resultlen = 0;
14
0
    Py_UCS1 sep_char = 0;
15
0
    unsigned int abs_bytes_per_sep;
16
17
0
    if (sep) {
18
0
        Py_ssize_t seplen = PyObject_Length((PyObject*)sep);
19
0
        if (seplen < 0) {
20
0
            return NULL;
21
0
        }
22
0
        if (seplen != 1) {
23
0
            PyErr_SetString(PyExc_ValueError, "sep must be length 1.");
24
0
            return NULL;
25
0
        }
26
0
        if (PyUnicode_Check(sep)) {
27
0
            if (PyUnicode_READY(sep))
28
0
                return NULL;
29
0
            if (PyUnicode_KIND(sep) != PyUnicode_1BYTE_KIND) {
30
0
                PyErr_SetString(PyExc_ValueError, "sep must be ASCII.");
31
0
                return NULL;
32
0
            }
33
0
            sep_char = PyUnicode_READ_CHAR(sep, 0);
34
0
        } else if (PyBytes_Check(sep)) {
35
0
            sep_char = PyBytes_AS_STRING(sep)[0];
36
0
        } else {
37
0
            PyErr_SetString(PyExc_TypeError, "sep must be str or bytes.");
38
0
            return NULL;
39
0
        }
40
0
        if (sep_char > 127 && !return_bytes) {
41
0
            PyErr_SetString(PyExc_ValueError, "sep must be ASCII.");
42
0
            return NULL;
43
0
        }
44
0
    } else {
45
0
        bytes_per_sep_group = 0;
46
0
    }
47
48
0
    assert(arglen >= 0);
49
0
    abs_bytes_per_sep = abs(bytes_per_sep_group);
50
0
    if (bytes_per_sep_group && arglen > 0) {
51
        /* How many sep characters we'll be inserting. */
52
0
        resultlen = (arglen - 1) / abs_bytes_per_sep;
53
0
    }
54
    /* Bounds checking for our Py_ssize_t indices. */
55
0
    if (arglen >= PY_SSIZE_T_MAX / 2 - resultlen) {
56
0
        return PyErr_NoMemory();
57
0
    }
58
0
    resultlen += arglen * 2;
59
60
0
    if ((size_t)abs_bytes_per_sep >= (size_t)arglen) {
61
0
        bytes_per_sep_group = 0;
62
0
        abs_bytes_per_sep = 0;
63
0
    }
64
65
0
    if (return_bytes) {
66
        /* If _PyBytes_FromSize() were public we could avoid malloc+copy. */
67
0
        retbuf = (Py_UCS1*) PyMem_Malloc(resultlen);
68
0
        if (!retbuf)
69
0
            return PyErr_NoMemory();
70
0
        retval = NULL;  /* silence a compiler warning, assigned later. */
71
0
    } else {
72
0
        retval = PyUnicode_New(resultlen, 127);
73
0
        if (!retval)
74
0
            return NULL;
75
0
        retbuf = PyUnicode_1BYTE_DATA(retval);
76
0
    }
77
78
    /* Hexlify */
79
0
    for (i=j=0; i < arglen; ++i) {
80
0
        assert(j < resultlen);
81
0
        unsigned char c;
82
0
        c = (argbuf[i] >> 4) & 0xf;
83
0
        retbuf[j++] = Py_hexdigits[c];
84
0
        c = argbuf[i] & 0xf;
85
0
        retbuf[j++] = Py_hexdigits[c];
86
0
        if (bytes_per_sep_group && i < arglen - 1) {
87
0
            Py_ssize_t anchor;
88
0
            anchor = (bytes_per_sep_group > 0) ? (arglen - 1 - i) : (i + 1);
89
0
            if (anchor % abs_bytes_per_sep == 0) {
90
0
                retbuf[j++] = sep_char;
91
0
            }
92
0
        }
93
0
    }
94
0
    assert(j == resultlen);
95
96
0
    if (return_bytes) {
97
0
        retval = PyBytes_FromStringAndSize((const char *)retbuf, resultlen);
98
0
        PyMem_Free(retbuf);
99
0
    }
100
#ifdef Py_DEBUG
101
    else {
102
        assert(_PyUnicode_CheckConsistency(retval, 1));
103
    }
104
#endif
105
106
0
    return retval;
107
0
}
108
109
PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen)
110
0
{
111
0
    return _Py_strhex_impl(argbuf, arglen, NULL, 0, 0);
112
0
}
113
114
/* Same as above but returns a bytes() instead of str() to avoid the
115
 * need to decode the str() when bytes are needed. */
116
PyObject * _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen)
117
0
{
118
0
    return _Py_strhex_impl(argbuf, arglen, NULL, 0, 1);
119
0
}
120
121
/* These variants include support for a separator between every N bytes: */
122
123
PyObject * _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, const PyObject* sep, const int bytes_per_group)
124
0
{
125
0
    return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 0);
126
0
}
127
128
/* Same as above but returns a bytes() instead of str() to avoid the
129
 * need to decode the str() when bytes are needed. */
130
PyObject * _Py_strhex_bytes_with_sep(const char* argbuf, const Py_ssize_t arglen, const PyObject* sep, const int bytes_per_group)
131
0
{
132
0
    return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 1);
133
0
}