blob: 9d34f71a2e9cf3e33f4fdd8d7185a1a7d7746068 [file] [log] [blame]
Gregory P. Smithe3f63932015-04-26 00:41:00 +00001/* bytes to hex implementation */
2
3#include "Python.h"
4
Benjamin Petersone5024512018-09-12 12:06:42 -07005#include "pystrhex.h"
6
Gregory P. Smithe3f63932015-04-26 00:41:00 +00007static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen,
Gregory P. Smith0c2f9302019-05-29 11:46:58 -07008 const PyObject* sep, int bytes_per_sep_group,
9 const int return_bytes)
Gregory P. Smithe3f63932015-04-26 00:41:00 +000010{
11 PyObject *retval;
12 Py_UCS1* retbuf;
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070013 Py_ssize_t i, j, resultlen = 0;
Pablo Galindo938d9a02019-06-01 21:02:08 +010014 Py_UCS1 sep_char = 0;
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070015 unsigned int abs_bytes_per_sep;
16
17 if (sep) {
Pablo Galindo938d9a02019-06-01 21:02:08 +010018 Py_ssize_t seplen = PyObject_Length((PyObject*)sep);
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070019 if (seplen < 0) {
20 return NULL;
21 }
22 if (seplen != 1) {
23 PyErr_SetString(PyExc_ValueError, "sep must be length 1.");
24 return NULL;
25 }
26 if (PyUnicode_Check(sep)) {
27 if (PyUnicode_READY(sep))
28 return NULL;
29 if (PyUnicode_KIND(sep) != PyUnicode_1BYTE_KIND) {
30 PyErr_SetString(PyExc_ValueError, "sep must be ASCII.");
31 return NULL;
32 }
33 sep_char = PyUnicode_READ_CHAR(sep, 0);
34 } else if (PyBytes_Check(sep)) {
35 sep_char = PyBytes_AS_STRING(sep)[0];
36 } else {
37 PyErr_SetString(PyExc_TypeError, "sep must be str or bytes.");
38 return NULL;
39 }
40 if (sep_char > 127 && !return_bytes) {
41 PyErr_SetString(PyExc_ValueError, "sep must be ASCII.");
42 return NULL;
43 }
44 } else {
45 bytes_per_sep_group = 0;
46 }
Gregory P. Smithe3f63932015-04-26 00:41:00 +000047
48 assert(arglen >= 0);
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070049 abs_bytes_per_sep = abs(bytes_per_sep_group);
50 if (bytes_per_sep_group && arglen > 0) {
51 /* How many sep characters we'll be inserting. */
52 resultlen = (arglen - 1) / abs_bytes_per_sep;
53 }
54 /* Bounds checking for our Py_ssize_t indices. */
55 if (arglen >= PY_SSIZE_T_MAX / 2 - resultlen) {
Gregory P. Smithe3f63932015-04-26 00:41:00 +000056 return PyErr_NoMemory();
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070057 }
58 resultlen += arglen * 2;
59
Raymond Hettinger0138c4c2019-08-27 09:55:13 -070060 if ((size_t)abs_bytes_per_sep >= (size_t)arglen) {
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070061 bytes_per_sep_group = 0;
62 abs_bytes_per_sep = 0;
63 }
Gregory P. Smithe3f63932015-04-26 00:41:00 +000064
65 if (return_bytes) {
66 /* If _PyBytes_FromSize() were public we could avoid malloc+copy. */
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070067 retbuf = (Py_UCS1*) PyMem_Malloc(resultlen);
Serhiy Storchaka598ceae2017-11-28 17:56:10 +020068 if (!retbuf)
69 return PyErr_NoMemory();
Gregory P. Smithf7894652015-04-25 23:51:39 -070070 retval = NULL; /* silence a compiler warning, assigned later. */
Gregory P. Smithe3f63932015-04-26 00:41:00 +000071 } else {
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070072 retval = PyUnicode_New(resultlen, 127);
Serhiy Storchaka598ceae2017-11-28 17:56:10 +020073 if (!retval)
74 return NULL;
75 retbuf = PyUnicode_1BYTE_DATA(retval);
Gregory P. Smithe3f63932015-04-26 00:41:00 +000076 }
77
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070078 /* Hexlify */
79 for (i=j=0; i < arglen; ++i) {
80 assert(j < resultlen);
Gregory P. Smithe3f63932015-04-26 00:41:00 +000081 unsigned char c;
82 c = (argbuf[i] >> 4) & 0xf;
83 retbuf[j++] = Py_hexdigits[c];
84 c = argbuf[i] & 0xf;
85 retbuf[j++] = Py_hexdigits[c];
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070086 if (bytes_per_sep_group && i < arglen - 1) {
87 Py_ssize_t anchor;
88 anchor = (bytes_per_sep_group > 0) ? (arglen - 1 - i) : (i + 1);
89 if (anchor % abs_bytes_per_sep == 0) {
90 retbuf[j++] = sep_char;
91 }
92 }
Gregory P. Smithe3f63932015-04-26 00:41:00 +000093 }
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070094 assert(j == resultlen);
Gregory P. Smithe3f63932015-04-26 00:41:00 +000095
96 if (return_bytes) {
Gregory P. Smith0c2f9302019-05-29 11:46:58 -070097 retval = PyBytes_FromStringAndSize((const char *)retbuf, resultlen);
Gregory P. Smithe3f63932015-04-26 00:41:00 +000098 PyMem_Free(retbuf);
99 }
100#ifdef Py_DEBUG
101 else {
102 assert(_PyUnicode_CheckConsistency(retval, 1));
103 }
104#endif
105
106 return retval;
107}
108
Benjamin Petersone5024512018-09-12 12:06:42 -0700109PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen)
Gregory P. Smithe3f63932015-04-26 00:41:00 +0000110{
Gregory P. Smith0c2f9302019-05-29 11:46:58 -0700111 return _Py_strhex_impl(argbuf, arglen, NULL, 0, 0);
Gregory P. Smithe3f63932015-04-26 00:41:00 +0000112}
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. */
Benjamin Petersone5024512018-09-12 12:06:42 -0700116PyObject * _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen)
Gregory P. Smithe3f63932015-04-26 00:41:00 +0000117{
Gregory P. Smith0c2f9302019-05-29 11:46:58 -0700118 return _Py_strhex_impl(argbuf, arglen, NULL, 0, 1);
119}
120
121/* These variants include support for a separator between every N bytes: */
122
123PyObject * _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, const PyObject* sep, const int bytes_per_group)
124{
125 return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 0);
126}
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. */
130PyObject * _Py_strhex_bytes_with_sep(const char* argbuf, const Py_ssize_t arglen, const PyObject* sep, const int bytes_per_group)
131{
132 return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 1);
Gregory P. Smithe3f63932015-04-26 00:41:00 +0000133}