Branch data 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 : 26840 : 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 : : assert(arglen >= 0); 12 : : 13 : 26840 : Py_UCS1 sep_char = 0; 14 [ + + ]: 26840 : 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 : 26743 : bytes_per_sep_group = 0; 46 : : } 47 : : 48 : 26826 : unsigned int abs_bytes_per_sep = abs(bytes_per_sep_group); 49 : 26826 : Py_ssize_t resultlen = 0; 50 [ + + + - ]: 26826 : 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 [ - + ]: 26826 : if (arglen >= PY_SSIZE_T_MAX / 2 - resultlen) { 56 : : return PyErr_NoMemory(); 57 : : } 58 : 26826 : resultlen += arglen * 2; 59 : : 60 [ + + ]: 26826 : 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 [ + + ]: 26826 : 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 : 26559 : retval = PyUnicode_New(resultlen, 127); 77 [ - + ]: 26559 : if (!retval) { 78 : 0 : return NULL; 79 : : } 80 : 26559 : retbuf = PyUnicode_1BYTE_DATA(retval); 81 : : } 82 : : 83 : : /* Hexlify */ 84 : : Py_ssize_t i, j; 85 : : unsigned char c; 86 : : 87 [ + + ]: 26826 : if (bytes_per_sep_group == 0) { 88 [ + + ]: 1952778 : for (i = j = 0; i < arglen; ++i) { 89 : : assert((j + 1) < resultlen); 90 : 1926017 : c = argbuf[i]; 91 : 1926017 : retbuf[j++] = Py_hexdigits[c >> 4]; 92 : 1926017 : retbuf[j++] = Py_hexdigits[c & 0x0f]; 93 : : } 94 : : 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 : : 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 : : assert(j == -1); 136 : : } 137 : : } 138 : : 139 : : #ifdef Py_DEBUG 140 : : if (!return_bytes) { 141 : : assert(_PyUnicode_CheckConsistency(retval, 1)); 142 : : } 143 : : #endif 144 : : 145 : 26826 : 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 : 11448 : PyObject* _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, 163 : : PyObject* sep, const int bytes_per_group) 164 : : { 165 : 11448 : 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 : : }