8000 Accept bytes in bytes.fromhex()/bytearray.fromhex() · lordmauve/cpython@81d7ea2 · GitHub
[go: up one dir, main page]

8000
Skip to content

Commit 81d7ea2

Browse files
committed
Accept bytes in bytes.fromhex()/bytearray.fromhex()
Fixes python#129349
1 parent 155c44b commit 81d7ea2

File tree

6 files changed

+46
-67
lines changed

6 files changed

+46
-67
lines changed

Lib/test/test_bytes.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,14 @@ def test_fromhex(self):
455455
for c in "\x1C\x1D\x1E\x1F\x85\xa0\u2000\u2002\u2028":
456456
self.assertRaises(ValueError, self.type2test.fromhex, c)
457457

458+
# Check that we can parse bytes and bytearray
459+
self.assertEqual(self.type2test.fromhex(b' 012abc'), b'\x01\x2a\xbc')
460+
self.assertEqual(
461+
self.type2test.fromhex(bytearray(b' 012abc')),
462+
b'\x01\x2a\xbc',
463+
)
464+
458465
self.assertEqual(self.type2test.fromhex('0000'), b'\0\0')
459-
self.assertRaises(TypeError, self.type2test.fromhex, b'1B')
460466
self.assertRaises(ValueError, self.type2test.fromhex, 'a')
461467
self.assertRaises(ValueError, self.type2test.fromhex, 'rt')
462468
self.assertRaises(ValueError, self.type2test.fromhex, '1a b cd')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``bytes.fromhex()``/``bytearray.fromhex()`` now accept ASCII ``bytes``.

Objects/bytearrayobject.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,7 +2533,7 @@ bytearray_splitlines_impl(PyByteArrayObject *self, int keepends)
25332533
@classmethod
25342534
bytearray.fromhex
25352535
2536-
string: unicode
2536+
string: object
25372537
/
25382538
25392539
Create a bytearray object from a string of hexadecimal numbers.
@@ -2543,8 +2543,8 @@ Example: bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef')
25432543
[clinic start generated code]*/
25442544

25452545
static PyObject *
2546-
bytearray_fromhex_impl(PyTypeObject *type, PyObject *string)
2547-
/*[clinic end generated code: output=8f0f0b6d30fb3ba0 input=f033a16d1fb21f48]*/
2546+
bytearray_fromhex(PyTypeObject *type, PyObject *string)
2547+
/*[clinic end generated code: output=da84dc708e9c4b36 input=7e314e5b2d7ab484]*/
25482548
{
25492549
PyObject *result = _PyBytes_FromHex(string, type == &PyByteArray_Type);
25502550
if (type != &PyByteArray_Type && result != NULL) {

Objects/bytesobject.c

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2484,7 +2484,7 @@ bytes_splitlines_impl(PyBytesObject *self, int keepends)
24842484
@classmethod
24852485
bytes.fromhex
24862486
2487-
string: unicode
2487+
string: object
24882488
/
24892489
24902490
Create a bytes object from a string of hexadecimal numbers.
@@ -2494,8 +2494,8 @@ Example: bytes.fromhex('B9 01EF') -> b'\\xb9\\x01\\xef'.
24942494
[clinic start generated code]*/
24952495

24962496
static PyObject *
2497-
bytes_fromhex_impl(PyTypeObject *type, PyObject *string)
2498-
/*[clinic end generated code: output=0973acc63661bb2e input=bf4d1c361670acd3]*/
2497+
bytes_fromhex(PyTypeObject *type, PyObject *string)
2498+
/*[clinic end generated code: output=d458ec88195da6b3 input=f37d98ed51088a21]*/
24992499
{
25002500
PyObject *result = _PyBytes_FromHex(string, 0);
25012501
if (type != &am EDBE p;PyBytes_Type && result != NULL) {
@@ -2510,31 +2510,43 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray)
25102510
char *buf;
25112511
Py_ssize_t hexlen, invalid_char;
25122512
unsigned int top, bot;
2513-
const Py_UCS1 *str, *end;
2513+
const Py_UCS1 *str, *start, *end;
25142514
_PyBytesWriter writer;
25152515

25162516
_PyBytesWriter_Init(&writer);
25172517
writer.use_bytearray = use_bytearray;
25182518

2519-
assert(PyUnicode_Check(string));
2520-
hexlen = PyUnicode_GET_LENGTH(string);
2519+
if (PyUnicode_Check(string)) {
2520+
hexlen = PyUnicode_GET_LENGTH(string);
25212521

2522-
if (!PyUnicode_IS_ASCII(string)) {
2523-
const void *data = PyUnicode_DATA(string);
2524-
int kind = PyUnicode_KIND(string);
2525-
Py_ssize_t i;
2522+
if (!PyUnicode_IS_ASCII(string)) {
2523+
const void *data = PyUnicode_DATA(string);
2524+
int kind = PyUnicode_KIND(string);
2525+
Py_ssize_t i;
25262526

2527-
/* search for the first non-ASCII character */
2528-
for (i = 0; i < hexlen; i++) {
2529-
if (PyUnicode_READ(kind, data, i) >= 128)
2530-
break;
2527+
/* search for the first non-ASCII character */
2528+
for (i = 0; i < hexlen; i++) {
2529+
if (PyUnicode_READ(kind, data, i) >= 128)
2530+
break;
2531+
}
2532+
invalid_char = i;
2533+
goto error;
25312534
}
2532-
invalid_char = i;
2533-
goto error;
2534-
}
25352535

2536-
assert(PyUnicode_KIND(string) == PyUnicode_1BYTE_KIND);
2537-
str = PyUnicode_1BYTE_DATA(string);
2536+
assert(PyUnicode_KIND(string) == PyUnicode_1BYTE_KIND);
2537+
str = start = PyUnicode_1BYTE_DATA(string);
2538+
} else if (PyBytes_Check(string)) {
2539+
hexlen = PyBytes_GET_SIZE(string);
2540+
str = start = (Py_UCS1 *) PyBytes_AS_STRING(string);
2541+
} else if (PyByteArray_Check(string)) {
2542+
hexlen = PyByteArray_GET_SIZE(string);
2543+
str = start = (Py_UCS1 *) PyByteArray_AS_STRING(string);
2544+
} else {
2545+
PyErr_Format(PyExc_TypeError,
2546+
"fromhex() argument must be str or bytes, not %s",
2547+
Py_TYPE(string)->tp_name);
2548+
return NULL;
2549+
}
25382550

25392551
/* This overestimates if there are spaces */
25402552
buf = _PyBytesWriter_Alloc(&writer, hexlen / 2);
@@ -2554,7 +2566,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray)
25542566

25552567
top = _PyLong_DigitValue[*str];
25562568
if (top >= 16) {
2557-
invalid_char = str - PyUnicode_1BYTE_DATA(string);
2569+
invalid_char = str - start;
25582570
goto error;
25592571
}
25602572
str++;
@@ -2565,7 +2577,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray)
25652577
if (str >= end){
25662578
invalid_char = -1;
25672579
} else {
2568-
invalid_char = str - PyUnicode_1BYTE_DATA(string);
2580+
invalid_char = str - start;
25692581
}
25702582
goto error;
25712583
}

Objects/clinic/bytearrayobject.c.h

Lines changed: 1 addition & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/clinic/bytesobject.c.h

Lines changed: 1 addition & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
0