Line data Source code
1 : /* Format bytes as hexadecimal */ 2 : 3 : #include "Python.h" 4 : #include "pycore_strhex.h" // _Py_strhex_with_sep() 5 : #include <stdlib.h> // abs() 6 : 7 26750 : static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen, 8 : PyObject* sep, int bytes_per_sep_group, 9 : const int return_bytes) 10 : { 11 26750 : assert(arglen >= 0); 12 : 13 26750 : Py_UCS1 sep_char = 0; 14 26750 : if (sep) { 15 97 : Py_ssize_t seplen = PyObject_Length((PyObject*)sep); 16 97 : if (seplen < 0) { 17 2 : return NULL; 18 : } 19 95 : if (seplen != 1) { 20 4 : PyErr_SetString(PyExc_ValueError, "sep must be length 1."); 21 4 : return NULL; 22 : } 23 91 : if (PyUnicode_Check(sep)) { 24 79 : if (PyUnicode_READY(sep)) 25 0 : return NULL; 26 79 : if (PyUnicode_KIND(sep) != PyUnicode_1BYTE_KIND) { 27 2 : PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); 28 2 : return NULL; 29 : } 30 77 : sep_char = PyUnicode_READ_CHAR(sep, 0); 31 : } 32 12 : else if (PyBytes_Check(sep)) { 33 12 : sep_char = PyBytes_AS_STRING(sep)[0]; 34 : } 35 : else { 36 0 : PyErr_SetString(PyExc_TypeError, "sep must be str or bytes."); 37 0 : return NULL; 38 : } 39 89 : if (sep_char > 127 && !return_bytes) { 40 6 : PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); 41 6 : return NULL; 42 : } 43 : } 44 : else { 45 26653 : bytes_per_sep_group = 0; 46 : } 47 : 48 26736 : unsigned int abs_bytes_per_sep = abs(bytes_per_sep_group); 49 26736 : Py_ssize_t resultlen = 0; 50 26736 : if (bytes_per_sep_group && arglen > 0) { 51 : /* How many sep characters we'll be inserting. */ 52 79 : resultlen = (arglen - 1) / abs_bytes_per_sep; 53 : } 54 : /* Bounds checking for our Py_ssize_t indices. */ 55 26736 : if (arglen >= PY_SSIZE_T_MAX / 2 - resultlen) { 56 0 : return PyErr_NoMemory(); 57 : } 58 26736 : resultlen += arglen * 2; 59 : 60 26736 : if ((size_t)abs_bytes_per_sep >= (size_t)arglen) { 61 25 : bytes_per_sep_group = 0; 62 25 : abs_bytes_per_sep = 0; 63 : } 64 : 65 : PyObject *retval; 66 : Py_UCS1 *retbuf; 67 26736 : if (return_bytes) { 68 : /* If _PyBytes_FromSize() were public we could avoid malloc+copy. */ 69 267 : retval = PyBytes_FromStringAndSize(NULL, resultlen); 70 267 : if (!retval) { 71 0 : return NULL; 72 : } 73 267 : retbuf = (Py_UCS1 *)PyBytes_AS_STRING(retval); 74 : } 75 : else { 76 26469 : retval = PyUnicode_New(resultlen, 127); 77 26469 : if (!retval) { 78 0 : return NULL; 79 : } 80 26469 : retbuf = PyUnicode_1BYTE_DATA(retval); 81 : } 82 : 83 : /* Hexlify */ 84 : Py_ssize_t i, j; 85 : unsigned char c; 86 : 87 26736 : if (bytes_per_sep_group == 0) { 88 1781860 : for (i = j = 0; i < arglen; ++i) { 89 1755190 : assert((j + 1) < resultlen); 90 1755190 : c = argbuf[i]; 91 1755190 : retbuf[j++] = Py_hexdigits[c >> 4]; 92 1755190 : retbuf[j++] = Py_hexdigits[c & 0x0f]; 93 : } 94 26671 : assert(j == resultlen); 95 : } 96 : else { 97 : /* The number of complete chunk+sep periods */ 98 65 : Py_ssize_t chunks = (arglen - 1) / abs_bytes_per_sep; 99 : Py_ssize_t chunk; 100 : unsigned int k; 101 : 102 65 : if (bytes_per_sep_group < 0) { 103 13 : i = j = 0; 104 28 : for (chunk = 0; chunk < chunks; chunk++) { 105 53 : for (k = 0; k < abs_bytes_per_sep; k++) { 106 38 : c = argbuf[i++]; 107 38 : retbuf[j++] = Py_hexdigits[c >> 4]; 108 38 : retbuf[j++] = Py_hexdigits[c & 0x0f]; 109 : } 110 15 : retbuf[j++] = sep_char; 111 : } 112 32 : while (i < arglen) { 113 19 : c = argbuf[i++]; 114 19 : retbuf[j++] = Py_hexdigits[c >> 4]; 115 19 : retbuf[j++] = Py_hexdigits[c & 0x0f]; 116 : } 117 13 : assert(j == resultlen); 118 : } 119 : else { 120 52 : i = arglen - 1; 121 52 : j = resultlen - 1; 122 393 : for (chunk = 0; chunk < chunks; chunk++) { 123 919 : for (k = 0; k < abs_bytes_per_sep; k++) { 124 578 : c = argbuf[i--]; 125 578 : retbuf[j--] = Py_hexdigits[c & 0x0f]; 126 578 : retbuf[j--] = Py_hexdigits[c >> 4]; 127 : } 128 341 : retbuf[j--] = sep_char; 129 : } 130 182 : while (i >= 0) { 131 130 : c = argbuf[i--]; 132 130 : retbuf[j--] = Py_hexdigits[c & 0x0f]; 133 130 : retbuf[j--] = Py_hexdigits[c >> 4]; 134 : } 135 52 : assert(j == -1); 136 : } 137 : } 138 : 139 : #ifdef Py_DEBUG 140 26736 : if (!return_bytes) { 141 26469 : assert(_PyUnicode_CheckConsistency(retval, 1)); 142 : } 143 : #endif 144 : 145 26736 : return retval; 146 : } 147 : 148 15125 : PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen) 149 : { 150 15125 : return _Py_strhex_impl(argbuf, arglen, NULL, 0, 0); 151 : } 152 : 153 : /* Same as above but returns a bytes() instead of str() to avoid the 154 : * need to decode the str() when bytes are needed. */ 155 0 : PyObject* _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen) 156 : { 157 0 : return _Py_strhex_impl(argbuf, arglen, NULL, 0, 1); 158 : } 159 : 160 : /* These variants include support for a separator between every N bytes: */ 161 : 162 11358 : PyObject* _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, 163 : PyObject* sep, const int bytes_per_group) 164 : { 165 11358 : return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 0); 166 : } 167 : 168 : /* Same as above but returns a bytes() instead of str() to avoid the 169 : * need to decode the str() when bytes are needed. */ 170 267 : PyObject* _Py_strhex_bytes_with_sep(const char* argbuf, const Py_ssize_t arglen, 171 : PyObject* sep, const int bytes_per_group) 172 : { 173 267 : return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 1); 174 : }