/home/mdboom/Work/builds/cpython/Python/pystrhex.c
Line | Count | Source (jump to first uncovered line) |
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 | 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 | Py_UCS1 sep_char = 0; |
14 | if (sep) { Branch (14:9): [True: 97, False: 12.8k]
|
15 | Py_ssize_t seplen = PyObject_Length((PyObject*)sep); |
16 | if (seplen < 0) { Branch (16:13): [True: 2, False: 95]
|
17 | return NULL; |
18 | } |
19 | if (seplen != 1) { Branch (19:13): [True: 4, False: 91]
|
20 | PyErr_SetString(PyExc_ValueError, "sep must be length 1."); |
21 | return NULL; |
22 | } |
23 | if (PyUnicode_Check(sep)) { |
24 | if (PyUnicode_READY(sep)) |
25 | return NULL; |
26 | if (PyUnicode_KIND(sep) != PyUnicode_1BYTE_KIND) { Branch (26:17): [True: 2, False: 77]
|
27 | PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); |
28 | return NULL; |
29 | } |
30 | sep_char = PyUnicode_READ_CHAR(sep, 0); |
31 | } |
32 | else if (PyBytes_Check(sep)) { |
33 | sep_char = PyBytes_AS_STRING(sep)[0]; |
34 | } |
35 | else { |
36 | PyErr_SetString(PyExc_TypeError, "sep must be str or bytes."); |
37 | return NULL; |
38 | } |
39 | if (sep_char > 127 && !return_bytes6 ) { Branch (39:13): [True: 6, False: 83]
Branch (39:31): [True: 6, False: 0]
|
40 | PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); |
41 | return NULL; |
42 | } |
43 | } |
44 | else { |
45 | bytes_per_sep_group = 0; |
46 | } |
47 | |
48 | unsigned int abs_bytes_per_sep = abs(bytes_per_sep_group); |
49 | Py_ssize_t resultlen = 0; |
50 | if (bytes_per_sep_group && arglen > 079 ) { Branch (50:9): [True: 79, False: 12.8k]
Branch (50:32): [True: 79, False: 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) { Branch (55:9): [True: 0, False: 12.9k]
|
56 | return PyErr_NoMemory(); |
57 | } |
58 | resultlen += arglen * 2; |
59 | |
60 | if ((size_t)abs_bytes_per_sep >= (size_t)arglen) { Branch (60:9): [True: 25, False: 12.9k]
|
61 | bytes_per_sep_group = 0; |
62 | abs_bytes_per_sep = 0; |
63 | } |
64 | |
65 | PyObject *retval; |
66 | Py_UCS1 *retbuf; |
67 | if (return_bytes) { Branch (67:9): [True: 264, False: 12.6k]
|
68 | /* If _PyBytes_FromSize() were public we could avoid malloc+copy. */ |
69 | retval = PyBytes_FromStringAndSize(NULL, resultlen); |
70 | if (!retval) { Branch (70:13): [True: 0, False: 264]
|
71 | return NULL; |
72 | } |
73 | retbuf = (Py_UCS1 *)PyBytes_AS_STRING(retval); |
74 | } |
75 | else { |
76 | retval = PyUnicode_New(resultlen, 127); |
77 | if (!retval) { Branch (77:13): [True: 0, False: 12.6k]
|
78 | return NULL; |
79 | } |
80 | retbuf = PyUnicode_1BYTE_DATA(retval); |
81 | } |
82 | |
83 | /* Hexlify */ |
84 | Py_ssize_t i, j; |
85 | unsigned char c; |
86 | |
87 | if (bytes_per_sep_group == 0) { Branch (87:9): [True: 12.8k, False: 65]
|
88 | for (i = j = 0; i < arglen; ++i612k ) { Branch (88:25): [True: 612k, False: 12.8k]
|
89 | assert((j + 1) < resultlen); |
90 | c = argbuf[i]; |
91 | retbuf[j++] = Py_hexdigits[c >> 4]; |
92 | retbuf[j++] = Py_hexdigits[c & 0x0f]; |
93 | } |
94 | assert(j == resultlen); |
95 | } |
96 | else { |
97 | /* The number of complete chunk+sep periods */ |
98 | Py_ssize_t chunks = (arglen - 1) / abs_bytes_per_sep; |
99 | Py_ssize_t chunk; |
100 | unsigned int k; |
101 | |
102 | if (bytes_per_sep_group < 0) { Branch (102:13): [True: 13, False: 52]
|
103 | i = j = 0; |
104 | for (chunk = 0; chunk < chunks; chunk++15 ) { Branch (104:29): [True: 15, False: 13]
|
105 | for (k = 0; k < abs_bytes_per_sep; k++38 ) { Branch (105:29): [True: 38, False: 15]
|
106 | c = argbuf[i++]; |
107 | retbuf[j++] = Py_hexdigits[c >> 4]; |
108 | retbuf[j++] = Py_hexdigits[c & 0x0f]; |
109 | } |
110 | retbuf[j++] = sep_char; |
111 | } |
112 | while (i < arglen) { Branch (112:20): [True: 19, False: 13]
|
113 | c = argbuf[i++]; |
114 | retbuf[j++] = Py_hexdigits[c >> 4]; |
115 | retbuf[j++] = Py_hexdigits[c & 0x0f]; |
116 | } |
117 | assert(j == resultlen); |
118 | } |
119 | else { |
120 | i = arglen - 1; |
121 | j = resultlen - 1; |
122 | for (chunk = 0; chunk < chunks; chunk++341 ) { Branch (122:29): [True: 341, False: 52]
|
123 | for (k = 0; k < abs_bytes_per_sep; k++578 ) { Branch (123:29): [True: 578, False: 341]
|
124 | c = argbuf[i--]; |
125 | retbuf[j--] = Py_hexdigits[c & 0x0f]; |
126 | retbuf[j--] = Py_hexdigits[c >> 4]; |
127 | } |
128 | retbuf[j--] = sep_char; |
129 | } |
130 | while (i >= 0) { Branch (130:20): [True: 130, False: 52]
|
131 | c = argbuf[i--]; |
132 | retbuf[j--] = Py_hexdigits[c & 0x0f]; |
133 | 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 | return retval; |
146 | } |
147 | |
148 | PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen) |
149 | { |
150 | 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 | PyObject* _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen) |
156 | { |
157 | 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 | PyObject* _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, |
163 | PyObject* sep, const int bytes_per_group) |
164 | { |
165 | 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 | PyObject* _Py_strhex_bytes_with_sep(const char* argbuf, const Py_ssize_t arglen, |
171 | PyObject* sep, const int bytes_per_group) |
172 | { |
173 | return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 1); |
174 | } |