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