@@ -30,6 +30,10 @@ static PyBytesObject *nullstring;
3030*/
3131#define PyBytesObject_SIZE (offsetof(PyBytesObject, ob_sval) + 1)
3232
33+ /* Forward declaration */
34+ Py_LOCAL_INLINE (Py_ssize_t ) _PyBytesWriter_GetSize (_PyBytesWriter * writer ,
35+ char * str );
36+
3337/*
3438 For PyBytes_FromString(), the parameter `str' points to a null-terminated
3539 string containing exactly `size' bytes.
@@ -3078,22 +3082,6 @@ bytes_splitlines_impl(PyBytesObject*self, int keepends)
30783082 );
30793083}
30803084
3081- static int
3082- hex_digit_to_int (Py_UCS4 c )
3083- {
3084- if (c >= 128 )
3085- return -1 ;
3086- if (Py_ISDIGIT (c ))
3087- return c - '0' ;
3088- else {
3089- if (Py_ISUPPER (c ))
3090- c = Py_TOLOWER (c );
3091- if (c >= 'a' && c <= 'f' )
3092- return c - 'a' + 10 ;
3093- }
3094- return -1 ;
3095- }
3096-
30973085/*[clinic input]
30983086@classmethod
30993087bytes.fromhex
@@ -3111,47 +3099,83 @@ static PyObject *
31113099bytes_fromhex_impl (PyTypeObject * type , PyObject * string )
31123100/*[clinic end generated code: output=0973acc63661bb2e input=bf4d1c361670acd3]*/
31133101{
3114- PyObject * newstring ;
3102+ return _PyBytes_FromHex (string , 0 );
3103+ }
3104+
3105+ PyObject *
3106+ _PyBytes_FromHex (PyObject * string , int use_bytearray )
3107+ {
31153108 char * buf ;
3116- Py_ssize_t hexlen , byteslen , i , j ;
3117- int top , bot ;
3118- void * data ;
3119- unsigned int kind ;
3109+ Py_ssize_t hexlen , invalid_char ;
3110+ unsigned int top , bot ;
3111+ Py_UCS1 * str , * end ;
3112+ _PyBytesWriter writer ;
3113+
3114+ _PyBytesWriter_Init (& writer );
3115+ writer .use_bytearray = use_bytearray ;
31203116
31213117 assert (PyUnicode_Check (string ));
31223118 if (PyUnicode_READY (string ))
31233119 return NULL ;
3124- kind = PyUnicode_KIND (string );
3125- data = PyUnicode_DATA (string );
31263120 hexlen = PyUnicode_GET_LENGTH (string );
31273121
3128- byteslen = hexlen /2 ; /* This overestimates if there are spaces */
3129- newstring = PyBytes_FromStringAndSize (NULL , byteslen );
3130- if (!newstring )
3122+ if (!PyUnicode_IS_ASCII (string )) {
3123+ void * data = PyUnicode_DATA (string );
3124+ unsigned int kind = PyUnicode_KIND (string );
3125+ Py_ssize_t i ;
3126+
3127+ /* search for the first non-ASCII character */
3128+ for (i = 0 ; i < hexlen ; i ++ ) {
3129+ if (PyUnicode_READ (kind , data , i ) >= 128 )
3130+ break ;
3131+ }
3132+ invalid_char = i ;
3133+ goto error ;
3134+ }
3135+
3136+ assert (PyUnicode_KIND (string ) == PyUnicode_1BYTE_KIND );
3137+ str = PyUnicode_1BYTE_DATA (string );
3138+
3139+ /* This overestimates if there are spaces */
3140+ buf = _PyBytesWriter_Alloc (& writer , hexlen / 2 );
3141+ if (buf == NULL )
31313142 return NULL ;
3132- buf = PyBytes_AS_STRING (newstring );
3133- for (i = j = 0 ; i < hexlen ; i += 2 ) {
3143+
3144+ end = str + hexlen ;
3145+ while (str < end ) {
31343146 /* skip over spaces in the input */
3135- while (PyUnicode_READ (kind , data , i ) == ' ' )
3136- i ++ ;
3137- if (i >= hexlen )
3138- break ;
3139- top = hex_digit_to_int (PyUnicode_READ (kind , data , i ));
3140- bot = hex_digit_to_int (PyUnicode_READ (kind , data , i + 1 ));
3141- if (top == -1 || bot == -1 ) {
3142- PyErr_Format (PyExc_ValueError ,
3143- "non-hexadecimal number found in "
3144- "fromhex() arg at position %zd" , i );
3147+ if (* str == ' ' ) {
3148+ do {
3149+ str ++ ;
3150+ } while (* str == ' ' );
3151+ if (str >= end )
3152+ break ;
3153+ }
3154+
3155+ top = _PyLong_DigitValue [* str ];
3156+ if (top >= 16 ) {
3157+ invalid_char = str - PyUnicode_1BYTE_DATA (string );
31453158 goto error ;
31463159 }
3147- buf [j ++ ] = (top << 4 ) + bot ;
3160+ str ++ ;
3161+
3162+ bot = _PyLong_DigitValue [* str ];
3163+ if (bot >= 16 ) {
3164+ invalid_char = str - PyUnicode_1BYTE_DATA (string );
3165+ goto error ;
3166+ }
3167+ str ++ ;
3168+
3169+ * buf ++ = (unsigned char )((top << 4 ) + bot );
31483170 }
3149- if (j != byteslen && _PyBytes_Resize (& newstring , j ) < 0 )
3150- goto error ;
3151- return newstring ;
3171+
3172+ return _PyBytesWriter_Finish (& writer , buf );
31523173
31533174 error :
3154- Py_XDECREF (newstring );
3175+ PyErr_Format (PyExc_ValueError ,
3176+ "non-hexadecimal number found in "
3177+ "fromhex() arg at position %zd" , invalid_char );
3178+ _PyBytesWriter_Dealloc (& writer );
31553179 return NULL ;
31563180}
31573181
@@ -3888,7 +3912,7 @@ _PyBytesWriter_AsString(_PyBytesWriter *writer)
38883912}
38893913
38903914Py_LOCAL_INLINE (Py_ssize_t )
3891- _PyBytesWriter_GetPos (_PyBytesWriter * writer , char * str )
3915+ _PyBytesWriter_GetSize (_PyBytesWriter * writer , char * str )
38923916{
38933917 char * start = _PyBytesWriter_AsString (writer );
38943918 assert (str != NULL );
@@ -3963,7 +3987,7 @@ _PyBytesWriter_Prepare(_PyBytesWriter *writer, void *str, Py_ssize_t size)
39633987 allocated += allocated / OVERALLOCATE_FACTOR ;
39643988 }
39653989
3966- pos = _PyBytesWriter_GetPos (writer , str );
3990+ pos = _PyBytesWriter_GetSize (writer , str );
39673991 if (!writer -> use_small_buffer ) {
39683992 if (writer -> use_bytearray ) {
39693993 if (PyByteArray_Resize (writer -> buffer , allocated ))
@@ -4041,33 +4065,33 @@ _PyBytesWriter_Alloc(_PyBytesWriter *writer, Py_ssize_t size)
40414065PyObject *
40424066_PyBytesWriter_Finish (_PyBytesWriter * writer , void * str )
40434067{
4044- Py_ssize_t pos ;
4068+ Py_ssize_t size ;
40454069 PyObject * result ;
40464070
40474071 _PyBytesWriter_CheckConsistency (writer , str );
40484072
4049- pos = _PyBytesWriter_GetPos (writer , str );
4050- if (pos == 0 && !writer -> use_bytearray ) {
4073+ size = _PyBytesWriter_GetSize (writer , str );
4074+ if (size == 0 && !writer -> use_bytearray ) {
40514075 Py_CLEAR (writer -> buffer );
40524076 /* Get the empty byte string singleton */
40534077 result = PyBytes_FromStringAndSize (NULL , 0 );
40544078 }
40554079 else if (writer -> use_small_buffer ) {
4056- result = PyBytes_FromStringAndSize (writer -> small_buffer , pos );
4080+ result = PyBytes_FromStringAndSize (writer -> small_buffer , size );
40574081 }
40584082 else {
40594083 result = writer -> buffer ;
40604084 writer -> buffer = NULL ;
40614085
4062- if (pos != writer -> allocated ) {
4086+ if (size != writer -> allocated ) {
40634087 if (writer -> use_bytearray ) {
4064- if (PyByteArray_Resize (result , pos )) {
4088+ if (PyByteArray_Resize (result , size )) {
40654089 Py_DECREF (result );
40664090 return NULL ;
40674091 }
40684092 }
40694093 else {
4070- if (_PyBytes_Resize (& result , pos )) {
4094+ if (_PyBytes_Resize (& result , size )) {
40714095 assert (result == NULL );
40724096 return NULL ;
40734097 }
0 commit comments