torsava / rpms / python3

Forked from rpms/python3 6 years ago
Clone
a9aa92d
Index: Objects/unicodeobject.c
a9aa92d
===================================================================
a9aa92d
--- Objects/unicodeobject.c	(revision 80382)
a9aa92d
+++ Objects/unicodeobject.c	(revision 80383)
a9aa92d
@@ -159,6 +159,12 @@
a9aa92d
        const Py_UNICODE *unicode, Py_ssize_t size, PyObject **exceptionObject,
a9aa92d
        Py_ssize_t startpos, Py_ssize_t endpos, Py_ssize_t *newpos);
a9aa92d
 
a9aa92d
+static void raise_encode_exception(PyObject **exceptionObject,
a9aa92d
+                                   const char *encoding,
a9aa92d
+                                   const Py_UNICODE *unicode, Py_ssize_t size,
a9aa92d
+                                   Py_ssize_t startpos, Py_ssize_t endpos,
a9aa92d
+                                   const char *reason);
a9aa92d
+
a9aa92d
 /* Same for linebreaks */
a9aa92d
 static unsigned char ascii_linebreak[] = {
a9aa92d
     0, 0, 0, 0, 0, 0, 0, 0,
a9aa92d
@@ -2461,61 +2467,88 @@
a9aa92d
             /* Encode Latin-1 */
a9aa92d
             *p++ = (char)(0xc0 | (ch >> 6));
a9aa92d
             *p++ = (char)(0x80 | (ch & 0x3f));
a9aa92d
-        }
a9aa92d
-        else {
a9aa92d
-            /* Encode UCS2 Unicode ordinals */
a9aa92d
-            if (ch < 0x10000) {
a9aa92d
+        } else if (0xD800 <= ch && ch <= 0xDFFF) {
a9aa92d
 #ifndef Py_UNICODE_WIDE
a9aa92d
-                /* Special case: check for high surrogate */
a9aa92d
-                if (0xD800 <= ch && ch <= 0xDBFF && i != size) {
a9aa92d
-                    Py_UCS4 ch2 = s[i];
a9aa92d
-                    /* Check for low surrogate and combine the two to
a9aa92d
-                       form a UCS4 value */
a9aa92d
-                    if (0xDC00 <= ch2 && ch2 <= 0xDFFF) {
a9aa92d
-                        ch = ((ch - 0xD800) << 10 | (ch2 - 0xDC00)) + 0x10000;
a9aa92d
-                        i++;
a9aa92d
-                        goto encodeUCS4;
a9aa92d
-                    }
a9aa92d
-                    /* Fall through: handles isolated high surrogates */
a9aa92d
-                }
a9aa92d
+            /* Special case: check for high and low surrogate */
a9aa92d
+            if (ch <= 0xDBFF && i != size && 0xDC00 <= s[i] && s[i] <= 0xDFFF) {
a9aa92d
+                Py_UCS4 ch2 = s[i];
a9aa92d
+                /* Combine the two surrogates to form a UCS4 value */
a9aa92d
+                ch = ((ch - 0xD800) << 10 | (ch2 - 0xDC00)) + 0x10000;
a9aa92d
+                i++;
a9aa92d
+
a9aa92d
+                /* Encode UCS4 Unicode ordinals */
a9aa92d
+                *p++ = (char)(0xf0 | (ch >> 18));
a9aa92d
+                *p++ = (char)(0x80 | ((ch >> 12) & 0x3f));
a9aa92d
+                *p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
a9aa92d
+                *p++ = (char)(0x80 | (ch & 0x3f));
a9aa92d
+
a9aa92d
 #endif
a9aa92d
-                if (ch >= 0xd800 && ch <= 0xdfff) {
a9aa92d
-                    Py_ssize_t newpos;
a9aa92d
-                    PyObject *rep;
a9aa92d
-                    char *prep;
a9aa92d
-                    int k;
a9aa92d
-                    rep = unicode_encode_call_errorhandler
a9aa92d
-                        (errors, &errorHandler, "utf-8", "surrogates not allowed", 
a9aa92d
-                         s, size, &exc, i-1, i, &newpos);
a9aa92d
-                    if (!rep)
a9aa92d
+            } else {
a9aa92d
+                Py_ssize_t newpos;
a9aa92d
+                PyObject *rep;
a9aa92d
+                Py_ssize_t repsize, k;
a9aa92d
+                rep = unicode_encode_call_errorhandler
a9aa92d
+                    (errors, &errorHandler, "utf-8", "surrogates not allowed",
a9aa92d
+                     s, size, &exc, i-1, i, &newpos);
a9aa92d
+                if (!rep)
a9aa92d
+                    goto error;
a9aa92d
+
a9aa92d
+                if (PyBytes_Check(rep))
a9aa92d
+                    repsize = PyBytes_GET_SIZE(rep);
a9aa92d
+                else
a9aa92d
+                    repsize = PyUnicode_GET_SIZE(rep);
a9aa92d
+
a9aa92d
+                if (repsize > 4) {
a9aa92d
+                    Py_ssize_t offset;
a9aa92d
+
a9aa92d
+                    if (result == NULL)
a9aa92d
+                        offset = p - stackbuf;
a9aa92d
+                    else
a9aa92d
+                        offset = p - PyBytes_AS_STRING(result);
a9aa92d
+
a9aa92d
+                    if (nallocated > PY_SSIZE_T_MAX - repsize + 4) {
a9aa92d
+                        /* integer overflow */
a9aa92d
+                        PyErr_NoMemory();
a9aa92d
                         goto error;
a9aa92d
-                    /* Implementation limitations: only support error handler that return
a9aa92d
-                       bytes, and only support up to four replacement bytes. */
a9aa92d
-                    if (!PyBytes_Check(rep)) {
a9aa92d
-                        PyErr_SetString(PyExc_TypeError, "error handler should have returned bytes");
a9aa92d
-                        Py_DECREF(rep);
a9aa92d
-                        goto error;
a9aa92d
                     }
a9aa92d
-                    if (PyBytes_Size(rep) > 4) {
a9aa92d
-                        PyErr_SetString(PyExc_TypeError, "error handler returned too many bytes");
a9aa92d
-                        Py_DECREF(rep);
a9aa92d
-                        goto error;
a9aa92d
+                    nallocated += repsize - 4;
a9aa92d
+                    if (result != NULL) {
a9aa92d
+                        if (_PyBytes_Resize(&result, nallocated) < 0)
a9aa92d
+                            goto error;
a9aa92d
+                    } else {
a9aa92d
+                        result = PyBytes_FromStringAndSize(NULL, nallocated);
a9aa92d
+                        if (result == NULL)
a9aa92d
+                            goto error;
a9aa92d
+                        Py_MEMCPY(PyBytes_AS_STRING(result), stackbuf, offset);
a9aa92d
                     }
a9aa92d
-                    prep = PyBytes_AsString(rep);
a9aa92d
-                    for(k = PyBytes_Size(rep); k > 0; k--)
a9aa92d
+                    p = PyBytes_AS_STRING(result) + offset;
a9aa92d
+                }
a9aa92d
+
a9aa92d
+                if (PyBytes_Check(rep)) {
a9aa92d
+                    char *prep = PyBytes_AS_STRING(rep);
a9aa92d
+                    for(k = repsize; k > 0; k--)
a9aa92d
                         *p++ = *prep++;
a9aa92d
-                    Py_DECREF(rep);
a9aa92d
-                    continue;
a9aa92d
-                    
a9aa92d
+                } else /* rep is unicode */ {
a9aa92d
+                    Py_UNICODE *prep = PyUnicode_AS_UNICODE(rep);
a9aa92d
+                    Py_UNICODE c;
a9aa92d
+
a9aa92d
+                    for(k=0; k
a9aa92d
+                        c = prep[k];
a9aa92d
+                        if (0x80 <= c) {
a9aa92d
+                            raise_encode_exception(&exc, "utf-8", s, size,
a9aa92d
+                                                   i-1, i, "surrogates not allowed");
a9aa92d
+                            goto error;
a9aa92d
+                        }
a9aa92d
+                        *p++ = (char)prep[k];
a9aa92d
+                    }
a9aa92d
                 }
a9aa92d
-                *p++ = (char)(0xe0 | (ch >> 12));
a9aa92d
-                *p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
a9aa92d
-                *p++ = (char)(0x80 | (ch & 0x3f));
a9aa92d
-                continue;
a9aa92d
+                Py_DECREF(rep);
a9aa92d
             }
a9aa92d
-#ifndef Py_UNICODE_WIDE
a9aa92d
-          encodeUCS4:
a9aa92d
-#endif
a9aa92d
+        } else if (ch < 0x10000) {
a9aa92d
+            *p++ = (char)(0xe0 | (ch >> 12));
a9aa92d
+            *p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
a9aa92d
+            *p++ = (char)(0x80 | (ch & 0x3f));
a9aa92d
+        } else /* ch >= 0x10000 */ {
a9aa92d
             /* Encode UCS4 Unicode ordinals */
a9aa92d
             *p++ = (char)(0xf0 | (ch >> 18));
a9aa92d
             *p++ = (char)(0x80 | ((ch >> 12) & 0x3f));
a9aa92d
Index: Lib/test/test_codecs.py
a9aa92d
===================================================================
a9aa92d
--- Lib/test/test_codecs.py	(revision 80382)
a9aa92d
+++ Lib/test/test_codecs.py	(revision 80383)
a9aa92d
@@ -571,6 +571,16 @@
a9aa92d
     def test_lone_surrogates(self):
a9aa92d
         self.assertRaises(UnicodeEncodeError, "\ud800".encode, "utf-8")
a9aa92d
         self.assertRaises(UnicodeDecodeError, b"\xed\xa0\x80".decode, "utf-8")
a9aa92d
+        self.assertEqual("[\uDC80]".encode("utf-8", "backslashreplace"),
a9aa92d
+                         b'[\\udc80]')
a9aa92d
+        self.assertEqual("[\uDC80]".encode("utf-8", "xmlcharrefreplace"),
a9aa92d
+                         b'[�]')
a9aa92d
+        self.assertEqual("[\uDC80]".encode("utf-8", "surrogateescape"),
a9aa92d
+                         b'[\x80]')
a9aa92d
+        self.assertEqual("[\uDC80]".encode("utf-8", "ignore"),
a9aa92d
+                         b'[]')
a9aa92d
+        self.assertEqual("[\uDC80]".encode("utf-8", "replace"),
a9aa92d
+                         b'[?]')
a9aa92d
 
a9aa92d
     def test_surrogatepass_handler(self):
a9aa92d
         self.assertEquals("abc\ud800def".encode("utf-8", "surrogatepass"),
a9aa92d