@@ -268,9 +268,10 @@ STRINGLIB(utf8_encoder)(PyObject *unicode,
268268 Py_ssize_t nallocated ; /* number of result bytes allocated */
269269 Py_ssize_t nneeded ; /* number of result bytes needed */
270270#if STRINGLIB_SIZEOF_CHAR > 1
271- PyObject * errorHandler = NULL ;
271+ PyObject * error_handler_obj = NULL ;
272272 PyObject * exc = NULL ;
273273 PyObject * rep = NULL ;
274+ _Py_error_handler error_handler = _Py_ERROR_UNKNOWN ;
274275#endif
275276#if STRINGLIB_SIZEOF_CHAR == 1
276277 const Py_ssize_t max_char_size = 2 ;
@@ -326,72 +327,116 @@ STRINGLIB(utf8_encoder)(PyObject *unicode,
326327 }
327328#if STRINGLIB_SIZEOF_CHAR > 1
328329 else if (Py_UNICODE_IS_SURROGATE (ch )) {
329- Py_ssize_t newpos ;
330- Py_ssize_t repsize , k , startpos ;
330+ Py_ssize_t startpos , endpos , newpos ;
331+ Py_ssize_t repsize , k ;
332+ if (error_handler == _Py_ERROR_UNKNOWN )
333+ error_handler = get_error_handler (errors );
334+
331335 startpos = i - 1 ;
332- rep = unicode_encode_call_errorhandler (
333- errors , & errorHandler , "utf-8" , "surrogates not allowed" ,
334- unicode , & exc , startpos , startpos + 1 , & newpos );
335- if (!rep )
336- goto error ;
337-
338- if (PyBytes_Check (rep ))
339- repsize = PyBytes_GET_SIZE (rep );
340- else
341- repsize = PyUnicode_GET_LENGTH (rep );
336+ endpos = startpos + 1 ;
337+
338+ while ((endpos < size ) && Py_UNICODE_IS_SURROGATE (data [endpos ]))
339+ endpos ++ ;
340+
341+ switch (error_handler )
342+ {
343+ case _Py_ERROR_REPLACE :
344+ memset (p , '?' , endpos - startpos );
345+ p += (endpos - startpos );
346+ /* fall through the ignore handler */
347+ case _Py_ERROR_IGNORE :
348+ i += (endpos - startpos - 1 );
349+ break ;
342350
343- if (repsize > max_char_size ) {
344- Py_ssize_t offset ;
345351
346- if (result == NULL )
347- offset = p - stackbuf ;
348- else
349- offset = p - PyBytes_AS_STRING (result );
352+ case _Py_ERROR_SURROGATEPASS :
353+ for (k = startpos ; k < endpos ; k ++ ) {
354+ ch = data [k ];
355+ * p ++ = (char )(0xe0 | (ch >> 12 ));
356+ * p ++ = (char )(0x80 | ((ch >> 6 ) & 0x3f ));
357+ * p ++ = (char )(0x80 | (ch & 0x3f ));
358+ }
359+ i += (endpos - startpos - 1 );
360+ break ;
350361
351- if (nallocated > PY_SSIZE_T_MAX - repsize + max_char_size ) {
352- /* integer overflow */
353- PyErr_NoMemory ();
354- goto error ;
362+ case _Py_ERROR_SURROGATEESCAPE :
363+ for (k = startpos ; k < endpos ; k ++ ) {
364+ ch = data [k ];
365+ if (!(0xDC80 <= ch && ch <= 0xDCFF ))
366+ break ;
367+ * p ++ = (char )(ch & 0xff );
355368 }
356- nallocated += repsize - max_char_size ;
357- if (result != NULL ) {
358- if (_PyBytes_Resize (& result , nallocated ) < 0 )
359- goto error ;
360- } else {
361- result = PyBytes_FromStringAndSize (NULL , nallocated );
369+ if (k >= endpos ) {
370+ i += (endpos - startpos - 1 );
371+ break ;
372+ }
373+ startpos = k ;
374+ assert (startpos < endpos );
375+ /* fall through the default handler */
376+
377+ default :
378+ rep = unicode_encode_call_errorhandler (
379+ errors , & error_handler_obj , "utf-8" , "surrogates not allowed" ,
380+ unicode , & exc , startpos , endpos , & newpos );
381+ if (!rep )
382+ goto error ;
383+
384+ if (PyBytes_Check (rep ))
385+ repsize = PyBytes_GET_SIZE (rep );
386+ else
387+ repsize = PyUnicode_GET_LENGTH (rep );
388+
389+ if (repsize > max_char_size ) {
390+ Py_ssize_t offset ;
391+
362392 if (result == NULL )
393+ offset = p - stackbuf ;
394+ else
395+ offset = p - PyBytes_AS_STRING (result );
396+
397+ if (nallocated > PY_SSIZE_T_MAX - repsize + max_char_size ) {
398+ /* integer overflow */
399+ PyErr_NoMemory ();
363400 goto error ;
364- Py_MEMCPY (PyBytes_AS_STRING (result ), stackbuf , offset );
401+ }
402+ nallocated += repsize - max_char_size ;
403+ if (result != NULL ) {
404+ if (_PyBytes_Resize (& result , nallocated ) < 0 )
405+ goto error ;
406+ } else {
407+ result = PyBytes_FromStringAndSize (NULL , nallocated );
408+ if (result == NULL )
409+ goto error ;
410+ Py_MEMCPY (PyBytes_AS_STRING (result ), stackbuf , offset );
411+ }
412+ p = PyBytes_AS_STRING (result ) + offset ;
365413 }
366- p = PyBytes_AS_STRING (result ) + offset ;
367- }
368-
369- if (PyBytes_Check (rep )) {
370- char * prep = PyBytes_AS_STRING (rep );
371- for (k = repsize ; k > 0 ; k -- )
372- * p ++ = * prep ++ ;
373- } else /* rep is unicode */ {
374- enum PyUnicode_Kind repkind ;
375- void * repdata ;
376414
377- if (PyUnicode_READY (rep ) < 0 )
378- goto error ;
379- repkind = PyUnicode_KIND (rep );
380- repdata = PyUnicode_DATA (rep );
415+ if (PyBytes_Check (rep )) {
416+ memcpy (p , PyBytes_AS_STRING (rep ), repsize );
417+ p += repsize ;
418+ }
419+ else {
420+ /* rep is unicode */
421+ if (PyUnicode_READY (rep ) < 0 )
422+ goto error ;
381423
382- for (k = 0 ; k < repsize ; k ++ ) {
383- Py_UCS4 c = PyUnicode_READ (repkind , repdata , k );
384- if (0x80 <= c ) {
424+ if (!PyUnicode_IS_ASCII (rep )) {
385425 raise_encode_exception (& exc , "utf-8" ,
386426 unicode ,
387427 i - 1 , i ,
388428 "surrogates not allowed" );
389429 goto error ;
390430 }
391- * p ++ = (char )c ;
431+
432+ assert (PyUnicode_KIND (rep ) == PyUnicode_1BYTE_KIND );
433+ memcpy (p , PyUnicode_DATA (rep ), repsize );
434+ p += repsize ;
392435 }
436+ Py_CLEAR (rep );
437+
438+ i = newpos ;
393439 }
394- Py_CLEAR (rep );
395440 }
396441 else
397442#if STRINGLIB_SIZEOF_CHAR > 2
@@ -430,15 +475,15 @@ STRINGLIB(utf8_encoder)(PyObject *unicode,
430475 }
431476
432477#if STRINGLIB_SIZEOF_CHAR > 1
433- Py_XDECREF (errorHandler );
478+ Py_XDECREF (error_handler_obj );
434479 Py_XDECREF (exc );
435480#endif
436481 return result ;
437482
438483#if STRINGLIB_SIZEOF_CHAR > 1
439484 error :
440485 Py_XDECREF (rep );
441- Py_XDECREF (errorHandler );
486+ Py_XDECREF (error_handler_obj );
442487 Py_XDECREF (exc );
443488 Py_XDECREF (result );
444489 return NULL ;
0 commit comments