/src/Python-3.8.3/Python/pystrhex.c
Line  | Count  | Source  | 
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  | }  |