LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/python3/Modules/cjkcodecs - multibytecodec.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 848 0.0 %
Date: 2012-12-17 Functions: 0 48 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * multibytecodec.c: Common Multibyte Codec Implementation
       3             :  *
       4             :  * Written by Hye-Shik Chang <perky@FreeBSD.org>
       5             :  */
       6             : 
       7             : #define PY_SSIZE_T_CLEAN
       8             : #include "Python.h"
       9             : #include "structmember.h"
      10             : #include "multibytecodec.h"
      11             : 
      12             : typedef struct {
      13             :     const Py_UNICODE    *inbuf, *inbuf_top, *inbuf_end;
      14             :     unsigned char       *outbuf, *outbuf_end;
      15             :     PyObject            *excobj, *outobj;
      16             : } MultibyteEncodeBuffer;
      17             : 
      18             : typedef struct {
      19             :     const unsigned char *inbuf, *inbuf_top, *inbuf_end;
      20             :     Py_UNICODE          *outbuf, *outbuf_end;
      21             :     PyObject            *excobj, *outobj;
      22             : } MultibyteDecodeBuffer;
      23             : 
      24             : PyDoc_STRVAR(MultibyteCodec_Encode__doc__,
      25             : "I.encode(unicode[, errors]) -> (string, length consumed)\n\
      26             : \n\
      27             : Return an encoded string version of `unicode'. errors may be given to\n\
      28             : set a different error handling scheme. Default is 'strict' meaning that\n\
      29             : encoding errors raise a UnicodeEncodeError. Other possible values are\n\
      30             : 'ignore', 'replace' and 'xmlcharrefreplace' as well as any other name\n\
      31             : registered with codecs.register_error that can handle UnicodeEncodeErrors.");
      32             : 
      33             : PyDoc_STRVAR(MultibyteCodec_Decode__doc__,
      34             : "I.decode(string[, errors]) -> (unicodeobject, length consumed)\n\
      35             : \n\
      36             : Decodes `string' using I, an MultibyteCodec instance. errors may be given\n\
      37             : to set a different error handling scheme. Default is 'strict' meaning\n\
      38             : that encoding errors raise a UnicodeDecodeError. Other possible values\n\
      39             : are 'ignore' and 'replace' as well as any other name registered with\n\
      40             : codecs.register_error that is able to handle UnicodeDecodeErrors.");
      41             : 
      42             : static char *codeckwarglist[] = {"input", "errors", NULL};
      43             : static char *incnewkwarglist[] = {"errors", NULL};
      44             : static char *incrementalkwarglist[] = {"input", "final", NULL};
      45             : static char *streamkwarglist[] = {"stream", "errors", NULL};
      46             : 
      47             : static PyObject *multibytecodec_encode(MultibyteCodec *,
      48             :                 MultibyteCodec_State *, const Py_UNICODE **, Py_ssize_t,
      49             :                 PyObject *, int);
      50             : 
      51             : #define MBENC_RESET     MBENC_MAX<<1 /* reset after an encoding session */
      52             : 
      53             : static PyObject *
      54           0 : make_tuple(PyObject *object, Py_ssize_t len)
      55             : {
      56             :     PyObject *v, *w;
      57             : 
      58           0 :     if (object == NULL)
      59           0 :         return NULL;
      60             : 
      61           0 :     v = PyTuple_New(2);
      62           0 :     if (v == NULL) {
      63           0 :         Py_DECREF(object);
      64           0 :         return NULL;
      65             :     }
      66           0 :     PyTuple_SET_ITEM(v, 0, object);
      67             : 
      68           0 :     w = PyLong_FromSsize_t(len);
      69           0 :     if (w == NULL) {
      70           0 :         Py_DECREF(v);
      71           0 :         return NULL;
      72             :     }
      73           0 :     PyTuple_SET_ITEM(v, 1, w);
      74             : 
      75           0 :     return v;
      76             : }
      77             : 
      78             : static PyObject *
      79           0 : internal_error_callback(const char *errors)
      80             : {
      81           0 :     if (errors == NULL || strcmp(errors, "strict") == 0)
      82           0 :         return ERROR_STRICT;
      83           0 :     else if (strcmp(errors, "ignore") == 0)
      84           0 :         return ERROR_IGNORE;
      85           0 :     else if (strcmp(errors, "replace") == 0)
      86           0 :         return ERROR_REPLACE;
      87             :     else
      88           0 :         return PyUnicode_FromString(errors);
      89             : }
      90             : 
      91             : static PyObject *
      92           0 : call_error_callback(PyObject *errors, PyObject *exc)
      93             : {
      94             :     PyObject *args, *cb, *r;
      95             :     const char *str;
      96             : 
      97             :     assert(PyUnicode_Check(errors));
      98           0 :     str = _PyUnicode_AsString(errors);
      99           0 :     if (str == NULL)
     100           0 :         return NULL;
     101           0 :     cb = PyCodec_LookupError(str);
     102           0 :     if (cb == NULL)
     103           0 :         return NULL;
     104             : 
     105           0 :     args = PyTuple_New(1);
     106           0 :     if (args == NULL) {
     107           0 :         Py_DECREF(cb);
     108           0 :         return NULL;
     109             :     }
     110             : 
     111           0 :     PyTuple_SET_ITEM(args, 0, exc);
     112           0 :     Py_INCREF(exc);
     113             : 
     114           0 :     r = PyObject_CallObject(cb, args);
     115           0 :     Py_DECREF(args);
     116           0 :     Py_DECREF(cb);
     117           0 :     return r;
     118             : }
     119             : 
     120             : static PyObject *
     121           0 : codecctx_errors_get(MultibyteStatefulCodecContext *self)
     122             : {
     123             :     const char *errors;
     124             : 
     125           0 :     if (self->errors == ERROR_STRICT)
     126           0 :         errors = "strict";
     127           0 :     else if (self->errors == ERROR_IGNORE)
     128           0 :         errors = "ignore";
     129           0 :     else if (self->errors == ERROR_REPLACE)
     130           0 :         errors = "replace";
     131             :     else {
     132           0 :         Py_INCREF(self->errors);
     133           0 :         return self->errors;
     134             :     }
     135             : 
     136           0 :     return PyUnicode_FromString(errors);
     137             : }
     138             : 
     139             : static int
     140           0 : codecctx_errors_set(MultibyteStatefulCodecContext *self, PyObject *value,
     141             :                     void *closure)
     142             : {
     143             :     PyObject *cb;
     144             :     const char *str;
     145             : 
     146           0 :     if (!PyUnicode_Check(value)) {
     147           0 :         PyErr_SetString(PyExc_TypeError, "errors must be a string");
     148           0 :         return -1;
     149             :     }
     150             : 
     151           0 :     str = _PyUnicode_AsString(value);
     152           0 :     if (str == NULL)
     153           0 :         return -1;
     154             : 
     155           0 :     cb = internal_error_callback(str);
     156           0 :     if (cb == NULL)
     157           0 :         return -1;
     158             : 
     159           0 :     ERROR_DECREF(self->errors);
     160           0 :     self->errors = cb;
     161           0 :     return 0;
     162             : }
     163             : 
     164             : /* This getset handlers list is used by all the stateful codec objects */
     165             : static PyGetSetDef codecctx_getsets[] = {
     166             :     {"errors",          (getter)codecctx_errors_get,
     167             :                     (setter)codecctx_errors_set,
     168             :                     PyDoc_STR("how to treat errors")},
     169             :     {NULL,}
     170             : };
     171             : 
     172             : static int
     173           0 : expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize)
     174             : {
     175             :     Py_ssize_t orgpos, orgsize, incsize;
     176             : 
     177           0 :     orgpos = (Py_ssize_t)((char *)buf->outbuf -
     178           0 :                             PyBytes_AS_STRING(buf->outobj));
     179           0 :     orgsize = PyBytes_GET_SIZE(buf->outobj);
     180           0 :     incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize);
     181             : 
     182           0 :     if (orgsize > PY_SSIZE_T_MAX - incsize)
     183           0 :         return -1;
     184             : 
     185           0 :     if (_PyBytes_Resize(&buf->outobj, orgsize + incsize) == -1)
     186           0 :         return -1;
     187             : 
     188           0 :     buf->outbuf = (unsigned char *)PyBytes_AS_STRING(buf->outobj) +orgpos;
     189           0 :     buf->outbuf_end = (unsigned char *)PyBytes_AS_STRING(buf->outobj)
     190           0 :         + PyBytes_GET_SIZE(buf->outobj);
     191             : 
     192           0 :     return 0;
     193             : }
     194             : #define REQUIRE_ENCODEBUFFER(buf, s) {                                  \
     195             :     if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end)             \
     196             :         if (expand_encodebuffer(buf, s) == -1)                          \
     197             :             goto errorexit;                                             \
     198             : }
     199             : 
     200             : static int
     201           0 : expand_decodebuffer(MultibyteDecodeBuffer *buf, Py_ssize_t esize)
     202             : {
     203             :     Py_ssize_t orgpos, orgsize;
     204             : 
     205           0 :     orgpos = (Py_ssize_t)(buf->outbuf - PyUnicode_AS_UNICODE(buf->outobj));
     206           0 :     orgsize = PyUnicode_GET_SIZE(buf->outobj);
     207           0 :     if (PyUnicode_Resize(&buf->outobj, orgsize + (
     208           0 :         esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize)) == -1)
     209           0 :         return -1;
     210             : 
     211           0 :     buf->outbuf = PyUnicode_AS_UNICODE(buf->outobj) + orgpos;
     212           0 :     buf->outbuf_end = PyUnicode_AS_UNICODE(buf->outobj)
     213           0 :                       + PyUnicode_GET_SIZE(buf->outobj);
     214             : 
     215           0 :     return 0;
     216             : }
     217             : #define REQUIRE_DECODEBUFFER(buf, s) {                                  \
     218             :     if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end)             \
     219             :         if (expand_decodebuffer(buf, s) == -1)                          \
     220             :             goto errorexit;                                             \
     221             : }
     222             : 
     223             : 
     224             : /**
     225             :  * MultibyteCodec object
     226             :  */
     227             : 
     228             : static int
     229           0 : multibytecodec_encerror(MultibyteCodec *codec,
     230             :                         MultibyteCodec_State *state,
     231             :                         MultibyteEncodeBuffer *buf,
     232             :                         PyObject *errors, Py_ssize_t e)
     233             : {
     234           0 :     PyObject *retobj = NULL, *retstr = NULL, *tobj;
     235             :     Py_ssize_t retstrsize, newpos;
     236             :     Py_ssize_t esize, start, end;
     237             :     const char *reason;
     238             : 
     239           0 :     if (e > 0) {
     240           0 :         reason = "illegal multibyte sequence";
     241           0 :         esize = e;
     242             :     }
     243             :     else {
     244           0 :         switch (e) {
     245             :         case MBERR_TOOSMALL:
     246           0 :             REQUIRE_ENCODEBUFFER(buf, -1);
     247           0 :             return 0; /* retry it */
     248             :         case MBERR_TOOFEW:
     249           0 :             reason = "incomplete multibyte sequence";
     250           0 :             esize = (Py_ssize_t)(buf->inbuf_end - buf->inbuf);
     251           0 :             break;
     252             :         case MBERR_INTERNAL:
     253           0 :             PyErr_SetString(PyExc_RuntimeError,
     254             :                             "internal codec error");
     255           0 :             return -1;
     256             :         default:
     257           0 :             PyErr_SetString(PyExc_RuntimeError,
     258             :                             "unknown runtime error");
     259           0 :             return -1;
     260             :         }
     261             :     }
     262             : 
     263           0 :     if (errors == ERROR_REPLACE) {
     264           0 :         const Py_UNICODE replchar = '?', *inbuf = &replchar;
     265             :         Py_ssize_t r;
     266             : 
     267             :         for (;;) {
     268             :             Py_ssize_t outleft;
     269             : 
     270           0 :             outleft = (Py_ssize_t)(buf->outbuf_end - buf->outbuf);
     271           0 :             r = codec->encode(state, codec->config, &inbuf, 1,
     272             :                               &buf->outbuf, outleft, 0);
     273           0 :             if (r == MBERR_TOOSMALL) {
     274           0 :                 REQUIRE_ENCODEBUFFER(buf, -1);
     275           0 :                 continue;
     276             :             }
     277             :             else
     278           0 :                 break;
     279           0 :         }
     280             : 
     281           0 :         if (r != 0) {
     282           0 :             REQUIRE_ENCODEBUFFER(buf, 1);
     283           0 :             *buf->outbuf++ = '?';
     284             :         }
     285             :     }
     286           0 :     if (errors == ERROR_IGNORE || errors == ERROR_REPLACE) {
     287           0 :         buf->inbuf += esize;
     288           0 :         return 0;
     289             :     }
     290             : 
     291           0 :     start = (Py_ssize_t)(buf->inbuf - buf->inbuf_top);
     292           0 :     end = start + esize;
     293             : 
     294             :     /* use cached exception object if available */
     295           0 :     if (buf->excobj == NULL) {
     296           0 :         buf->excobj = PyUnicodeEncodeError_Create(codec->encoding,
     297             :                         buf->inbuf_top,
     298           0 :                         buf->inbuf_end - buf->inbuf_top,
     299             :                         start, end, reason);
     300           0 :         if (buf->excobj == NULL)
     301           0 :             goto errorexit;
     302             :     }
     303             :     else
     304           0 :         if (PyUnicodeEncodeError_SetStart(buf->excobj, start) != 0 ||
     305           0 :             PyUnicodeEncodeError_SetEnd(buf->excobj, end) != 0 ||
     306           0 :             PyUnicodeEncodeError_SetReason(buf->excobj, reason) != 0)
     307             :             goto errorexit;
     308             : 
     309           0 :     if (errors == ERROR_STRICT) {
     310           0 :         PyCodec_StrictErrors(buf->excobj);
     311           0 :         goto errorexit;
     312             :     }
     313             : 
     314           0 :     retobj = call_error_callback(errors, buf->excobj);
     315           0 :     if (retobj == NULL)
     316           0 :         goto errorexit;
     317             : 
     318           0 :     if (!PyTuple_Check(retobj) || PyTuple_GET_SIZE(retobj) != 2 ||
     319           0 :         !PyUnicode_Check((tobj = PyTuple_GET_ITEM(retobj, 0))) ||
     320           0 :         !PyLong_Check(PyTuple_GET_ITEM(retobj, 1))) {
     321           0 :         PyErr_SetString(PyExc_TypeError,
     322             :                         "encoding error handler must return "
     323             :                         "(unicode, int) tuple");
     324           0 :         goto errorexit;
     325             :     }
     326             : 
     327             :     {
     328           0 :         const Py_UNICODE *uraw = PyUnicode_AS_UNICODE(tobj);
     329             : 
     330           0 :         retstr = multibytecodec_encode(codec, state, &uraw,
     331           0 :                         PyUnicode_GET_SIZE(tobj), ERROR_STRICT,
     332             :                         MBENC_FLUSH);
     333           0 :         if (retstr == NULL)
     334             :             goto errorexit;
     335             :     }
     336             : 
     337             :     assert(PyBytes_Check(retstr));
     338           0 :     retstrsize = PyBytes_GET_SIZE(retstr);
     339           0 :     REQUIRE_ENCODEBUFFER(buf, retstrsize);
     340             : 
     341           0 :     memcpy(buf->outbuf, PyBytes_AS_STRING(retstr), retstrsize);
     342           0 :     buf->outbuf += retstrsize;
     343             : 
     344           0 :     newpos = PyLong_AsSsize_t(PyTuple_GET_ITEM(retobj, 1));
     345           0 :     if (newpos < 0 && !PyErr_Occurred())
     346           0 :         newpos += (Py_ssize_t)(buf->inbuf_end - buf->inbuf_top);
     347           0 :     if (newpos < 0 || buf->inbuf_top + newpos > buf->inbuf_end) {
     348           0 :         PyErr_Clear();
     349           0 :         PyErr_Format(PyExc_IndexError,
     350             :                      "position %zd from error handler out of bounds",
     351             :                      newpos);
     352           0 :         goto errorexit;
     353             :     }
     354           0 :     buf->inbuf = buf->inbuf_top + newpos;
     355             : 
     356           0 :     Py_DECREF(retobj);
     357           0 :     Py_DECREF(retstr);
     358           0 :     return 0;
     359             : 
     360             : errorexit:
     361           0 :     Py_XDECREF(retobj);
     362           0 :     Py_XDECREF(retstr);
     363           0 :     return -1;
     364             : }
     365             : 
     366             : static int
     367           0 : multibytecodec_decerror(MultibyteCodec *codec,
     368             :                         MultibyteCodec_State *state,
     369             :                         MultibyteDecodeBuffer *buf,
     370             :                         PyObject *errors, Py_ssize_t e)
     371             : {
     372           0 :     PyObject *retobj = NULL, *retuni = NULL;
     373             :     Py_ssize_t retunisize, newpos;
     374             :     const char *reason;
     375             :     Py_ssize_t esize, start, end;
     376             : 
     377           0 :     if (e > 0) {
     378           0 :         reason = "illegal multibyte sequence";
     379           0 :         esize = e;
     380             :     }
     381             :     else {
     382           0 :         switch (e) {
     383             :         case MBERR_TOOSMALL:
     384           0 :             REQUIRE_DECODEBUFFER(buf, -1);
     385           0 :             return 0; /* retry it */
     386             :         case MBERR_TOOFEW:
     387           0 :             reason = "incomplete multibyte sequence";
     388           0 :             esize = (Py_ssize_t)(buf->inbuf_end - buf->inbuf);
     389           0 :             break;
     390             :         case MBERR_INTERNAL:
     391           0 :             PyErr_SetString(PyExc_RuntimeError,
     392             :                             "internal codec error");
     393           0 :             return -1;
     394             :         default:
     395           0 :             PyErr_SetString(PyExc_RuntimeError,
     396             :                             "unknown runtime error");
     397           0 :             return -1;
     398             :         }
     399             :     }
     400             : 
     401           0 :     if (errors == ERROR_REPLACE) {
     402           0 :         REQUIRE_DECODEBUFFER(buf, 1);
     403           0 :         *buf->outbuf++ = Py_UNICODE_REPLACEMENT_CHARACTER;
     404             :     }
     405           0 :     if (errors == ERROR_IGNORE || errors == ERROR_REPLACE) {
     406           0 :         buf->inbuf += esize;
     407           0 :         return 0;
     408             :     }
     409             : 
     410           0 :     start = (Py_ssize_t)(buf->inbuf - buf->inbuf_top);
     411           0 :     end = start + esize;
     412             : 
     413             :     /* use cached exception object if available */
     414           0 :     if (buf->excobj == NULL) {
     415           0 :         buf->excobj = PyUnicodeDecodeError_Create(codec->encoding,
     416           0 :                         (const char *)buf->inbuf_top,
     417           0 :                         (Py_ssize_t)(buf->inbuf_end - buf->inbuf_top),
     418             :                         start, end, reason);
     419           0 :         if (buf->excobj == NULL)
     420           0 :             goto errorexit;
     421             :     }
     422             :     else
     423           0 :         if (PyUnicodeDecodeError_SetStart(buf->excobj, start) ||
     424           0 :             PyUnicodeDecodeError_SetEnd(buf->excobj, end) ||
     425           0 :             PyUnicodeDecodeError_SetReason(buf->excobj, reason))
     426             :             goto errorexit;
     427             : 
     428           0 :     if (errors == ERROR_STRICT) {
     429           0 :         PyCodec_StrictErrors(buf->excobj);
     430           0 :         goto errorexit;
     431             :     }
     432             : 
     433           0 :     retobj = call_error_callback(errors, buf->excobj);
     434           0 :     if (retobj == NULL)
     435           0 :         goto errorexit;
     436             : 
     437           0 :     if (!PyTuple_Check(retobj) || PyTuple_GET_SIZE(retobj) != 2 ||
     438           0 :         !PyUnicode_Check((retuni = PyTuple_GET_ITEM(retobj, 0))) ||
     439           0 :         !PyLong_Check(PyTuple_GET_ITEM(retobj, 1))) {
     440           0 :         PyErr_SetString(PyExc_TypeError,
     441             :                         "decoding error handler must return "
     442             :                         "(unicode, int) tuple");
     443           0 :         goto errorexit;
     444             :     }
     445             : 
     446           0 :     if (PyUnicode_AsUnicode(retuni) == NULL)
     447           0 :         goto errorexit;
     448           0 :     retunisize = PyUnicode_GET_SIZE(retuni);
     449           0 :     if (retunisize > 0) {
     450           0 :         REQUIRE_DECODEBUFFER(buf, retunisize);
     451           0 :         memcpy((char *)buf->outbuf, PyUnicode_AS_UNICODE(retuni),
     452           0 :                         retunisize * Py_UNICODE_SIZE);
     453           0 :         buf->outbuf += retunisize;
     454             :     }
     455             : 
     456           0 :     newpos = PyLong_AsSsize_t(PyTuple_GET_ITEM(retobj, 1));
     457           0 :     if (newpos < 0 && !PyErr_Occurred())
     458           0 :         newpos += (Py_ssize_t)(buf->inbuf_end - buf->inbuf_top);
     459           0 :     if (newpos < 0 || buf->inbuf_top + newpos > buf->inbuf_end) {
     460           0 :         PyErr_Clear();
     461           0 :         PyErr_Format(PyExc_IndexError,
     462             :                      "position %zd from error handler out of bounds",
     463             :                      newpos);
     464           0 :         goto errorexit;
     465             :     }
     466           0 :     buf->inbuf = buf->inbuf_top + newpos;
     467           0 :     Py_DECREF(retobj);
     468           0 :     return 0;
     469             : 
     470             : errorexit:
     471           0 :     Py_XDECREF(retobj);
     472           0 :     return -1;
     473             : }
     474             : 
     475             : static PyObject *
     476           0 : multibytecodec_encode(MultibyteCodec *codec,
     477             :                       MultibyteCodec_State *state,
     478             :                       const Py_UNICODE **data, Py_ssize_t datalen,
     479             :                       PyObject *errors, int flags)
     480             : {
     481             :     MultibyteEncodeBuffer buf;
     482           0 :     Py_ssize_t finalsize, r = 0;
     483             : 
     484           0 :     if (datalen == 0 && !(flags & MBENC_RESET))
     485           0 :         return PyBytes_FromStringAndSize(NULL, 0);
     486             : 
     487           0 :     buf.excobj = NULL;
     488           0 :     buf.outobj = NULL;
     489           0 :     buf.inbuf = buf.inbuf_top = *data;
     490           0 :     buf.inbuf_end = buf.inbuf_top + datalen;
     491             : 
     492           0 :     if (datalen > (PY_SSIZE_T_MAX - 16) / 2) {
     493           0 :         PyErr_NoMemory();
     494           0 :         goto errorexit;
     495             :     }
     496             : 
     497           0 :     buf.outobj = PyBytes_FromStringAndSize(NULL, datalen * 2 + 16);
     498           0 :     if (buf.outobj == NULL)
     499           0 :         goto errorexit;
     500           0 :     buf.outbuf = (unsigned char *)PyBytes_AS_STRING(buf.outobj);
     501           0 :     buf.outbuf_end = buf.outbuf + PyBytes_GET_SIZE(buf.outobj);
     502             : 
     503           0 :     while (buf.inbuf < buf.inbuf_end) {
     504             :         Py_ssize_t inleft, outleft;
     505             : 
     506             :         /* we don't reuse inleft and outleft here.
     507             :          * error callbacks can relocate the cursor anywhere on buffer*/
     508           0 :         inleft = (Py_ssize_t)(buf.inbuf_end - buf.inbuf);
     509           0 :         outleft = (Py_ssize_t)(buf.outbuf_end - buf.outbuf);
     510           0 :         r = codec->encode(state, codec->config, &buf.inbuf, inleft,
     511             :                           &buf.outbuf, outleft, flags);
     512           0 :         if ((r == 0) || (r == MBERR_TOOFEW && !(flags & MBENC_FLUSH)))
     513             :             break;
     514           0 :         else if (multibytecodec_encerror(codec, state, &buf, errors,r))
     515           0 :             goto errorexit;
     516           0 :         else if (r == MBERR_TOOFEW)
     517           0 :             break;
     518             :     }
     519             : 
     520           0 :     if (codec->encreset != NULL && (flags & MBENC_RESET))
     521             :         for (;;) {
     522             :             Py_ssize_t outleft;
     523             : 
     524           0 :             outleft = (Py_ssize_t)(buf.outbuf_end - buf.outbuf);
     525           0 :             r = codec->encreset(state, codec->config, &buf.outbuf,
     526             :                                 outleft);
     527           0 :             if (r == 0)
     528           0 :                 break;
     529           0 :             else if (multibytecodec_encerror(codec, state,
     530             :                                              &buf, errors, r))
     531           0 :                 goto errorexit;
     532           0 :         }
     533             : 
     534           0 :     finalsize = (Py_ssize_t)((char *)buf.outbuf -
     535           0 :                              PyBytes_AS_STRING(buf.outobj));
     536             : 
     537           0 :     if (finalsize != PyBytes_GET_SIZE(buf.outobj))
     538           0 :         if (_PyBytes_Resize(&buf.outobj, finalsize) == -1)
     539           0 :             goto errorexit;
     540             : 
     541           0 :     *data = buf.inbuf;
     542           0 :     Py_XDECREF(buf.excobj);
     543           0 :     return buf.outobj;
     544             : 
     545             : errorexit:
     546           0 :     Py_XDECREF(buf.excobj);
     547           0 :     Py_XDECREF(buf.outobj);
     548           0 :     return NULL;
     549             : }
     550             : 
     551             : static PyObject *
     552           0 : MultibyteCodec_Encode(MultibyteCodecObject *self,
     553             :                       PyObject *args, PyObject *kwargs)
     554             : {
     555             :     MultibyteCodec_State state;
     556             :     Py_UNICODE *data;
     557             :     PyObject *errorcb, *r, *arg, *ucvt;
     558           0 :     const char *errors = NULL;
     559             :     Py_ssize_t datalen;
     560             : 
     561           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|z:encode",
     562             :                             codeckwarglist, &arg, &errors))
     563           0 :         return NULL;
     564             : 
     565           0 :     if (PyUnicode_Check(arg))
     566           0 :         ucvt = NULL;
     567             :     else {
     568           0 :         arg = ucvt = PyObject_Str(arg);
     569           0 :         if (arg == NULL)
     570           0 :             return NULL;
     571           0 :         else if (!PyUnicode_Check(arg)) {
     572           0 :             PyErr_SetString(PyExc_TypeError,
     573             :                 "couldn't convert the object to unicode.");
     574           0 :             Py_DECREF(ucvt);
     575           0 :             return NULL;
     576             :         }
     577             :     }
     578             : 
     579           0 :     data = PyUnicode_AsUnicodeAndSize(arg, &datalen);
     580           0 :     if (data == NULL) {
     581           0 :         Py_XDECREF(ucvt);
     582           0 :         return NULL;
     583             :     }
     584             : 
     585           0 :     errorcb = internal_error_callback(errors);
     586           0 :     if (errorcb == NULL) {
     587           0 :         Py_XDECREF(ucvt);
     588           0 :         return NULL;
     589             :     }
     590             : 
     591           0 :     if (self->codec->encinit != NULL &&
     592           0 :         self->codec->encinit(&state, self->codec->config) != 0)
     593           0 :         goto errorexit;
     594           0 :     r = multibytecodec_encode(self->codec, &state,
     595             :                     (const Py_UNICODE **)&data, datalen, errorcb,
     596             :                     MBENC_FLUSH | MBENC_RESET);
     597           0 :     if (r == NULL)
     598           0 :         goto errorexit;
     599             : 
     600           0 :     ERROR_DECREF(errorcb);
     601           0 :     Py_XDECREF(ucvt);
     602           0 :     return make_tuple(r, datalen);
     603             : 
     604             : errorexit:
     605           0 :     ERROR_DECREF(errorcb);
     606           0 :     Py_XDECREF(ucvt);
     607           0 :     return NULL;
     608             : }
     609             : 
     610             : static PyObject *
     611           0 : MultibyteCodec_Decode(MultibyteCodecObject *self,
     612             :                       PyObject *args, PyObject *kwargs)
     613             : {
     614             :     MultibyteCodec_State state;
     615             :     MultibyteDecodeBuffer buf;
     616             :     PyObject *errorcb;
     617             :     Py_buffer pdata;
     618           0 :     const char *data, *errors = NULL;
     619             :     Py_ssize_t datalen, finalsize;
     620             : 
     621           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|z:decode",
     622             :                             codeckwarglist, &pdata, &errors))
     623           0 :         return NULL;
     624           0 :     data = pdata.buf;
     625           0 :     datalen = pdata.len;
     626             : 
     627           0 :     errorcb = internal_error_callback(errors);
     628           0 :     if (errorcb == NULL) {
     629           0 :         PyBuffer_Release(&pdata);
     630           0 :         return NULL;
     631             :     }
     632             : 
     633           0 :     if (datalen == 0) {
     634           0 :         PyBuffer_Release(&pdata);
     635           0 :         ERROR_DECREF(errorcb);
     636           0 :         return make_tuple(PyUnicode_New(0, 0), 0);
     637             :     }
     638             : 
     639           0 :     buf.excobj = NULL;
     640           0 :     buf.inbuf = buf.inbuf_top = (unsigned char *)data;
     641           0 :     buf.inbuf_end = buf.inbuf_top + datalen;
     642           0 :     buf.outobj = PyUnicode_FromUnicode(NULL, datalen);
     643           0 :     if (buf.outobj == NULL)
     644           0 :         goto errorexit;
     645           0 :     buf.outbuf = PyUnicode_AS_UNICODE(buf.outobj);
     646           0 :     if (buf.outbuf == NULL)
     647           0 :         goto errorexit;
     648           0 :     buf.outbuf_end = buf.outbuf + PyUnicode_GET_SIZE(buf.outobj);
     649             : 
     650           0 :     if (self->codec->decinit != NULL &&
     651           0 :         self->codec->decinit(&state, self->codec->config) != 0)
     652           0 :         goto errorexit;
     653             : 
     654           0 :     while (buf.inbuf < buf.inbuf_end) {
     655             :         Py_ssize_t inleft, outleft, r;
     656             : 
     657           0 :         inleft = (Py_ssize_t)(buf.inbuf_end - buf.inbuf);
     658           0 :         outleft = (Py_ssize_t)(buf.outbuf_end - buf.outbuf);
     659             : 
     660           0 :         r = self->codec->decode(&state, self->codec->config,
     661             :                         &buf.inbuf, inleft, &buf.outbuf, outleft);
     662           0 :         if (r == 0)
     663           0 :             break;
     664           0 :         else if (multibytecodec_decerror(self->codec, &state,
     665             :                                          &buf, errorcb, r))
     666           0 :             goto errorexit;
     667             :     }
     668             : 
     669           0 :     finalsize = (Py_ssize_t)(buf.outbuf -
     670           0 :                              PyUnicode_AS_UNICODE(buf.outobj));
     671             : 
     672           0 :     if (finalsize != PyUnicode_GET_SIZE(buf.outobj))
     673           0 :         if (PyUnicode_Resize(&buf.outobj, finalsize) == -1)
     674           0 :             goto errorexit;
     675             : 
     676           0 :     PyBuffer_Release(&pdata);
     677           0 :     Py_XDECREF(buf.excobj);
     678           0 :     ERROR_DECREF(errorcb);
     679           0 :     return make_tuple(buf.outobj, datalen);
     680             : 
     681             : errorexit:
     682           0 :     PyBuffer_Release(&pdata);
     683           0 :     ERROR_DECREF(errorcb);
     684           0 :     Py_XDECREF(buf.excobj);
     685           0 :     Py_XDECREF(buf.outobj);
     686             : 
     687           0 :     return NULL;
     688             : }
     689             : 
     690             : static struct PyMethodDef multibytecodec_methods[] = {
     691             :     {"encode",          (PyCFunction)MultibyteCodec_Encode,
     692             :                     METH_VARARGS | METH_KEYWORDS,
     693             :                     MultibyteCodec_Encode__doc__},
     694             :     {"decode",          (PyCFunction)MultibyteCodec_Decode,
     695             :                     METH_VARARGS | METH_KEYWORDS,
     696             :                     MultibyteCodec_Decode__doc__},
     697             :     {NULL,              NULL},
     698             : };
     699             : 
     700             : static void
     701           0 : multibytecodec_dealloc(MultibyteCodecObject *self)
     702             : {
     703           0 :     PyObject_Del(self);
     704           0 : }
     705             : 
     706             : static PyTypeObject MultibyteCodec_Type = {
     707             :     PyVarObject_HEAD_INIT(NULL, 0)
     708             :     "MultibyteCodec",                   /* tp_name */
     709             :     sizeof(MultibyteCodecObject),       /* tp_basicsize */
     710             :     0,                                  /* tp_itemsize */
     711             :     /* methods */
     712             :     (destructor)multibytecodec_dealloc, /* tp_dealloc */
     713             :     0,                                  /* tp_print */
     714             :     0,                                  /* tp_getattr */
     715             :     0,                                  /* tp_setattr */
     716             :     0,                                  /* tp_reserved */
     717             :     0,                                  /* tp_repr */
     718             :     0,                                  /* tp_as_number */
     719             :     0,                                  /* tp_as_sequence */
     720             :     0,                                  /* tp_as_mapping */
     721             :     0,                                  /* tp_hash */
     722             :     0,                                  /* tp_call */
     723             :     0,                                  /* tp_str */
     724             :     PyObject_GenericGetAttr,            /* tp_getattro */
     725             :     0,                                  /* tp_setattro */
     726             :     0,                                  /* tp_as_buffer */
     727             :     Py_TPFLAGS_DEFAULT,                 /* tp_flags */
     728             :     0,                                  /* tp_doc */
     729             :     0,                                  /* tp_traverse */
     730             :     0,                                  /* tp_clear */
     731             :     0,                                  /* tp_richcompare */
     732             :     0,                                  /* tp_weaklistoffset */
     733             :     0,                                  /* tp_iter */
     734             :     0,                                  /* tp_iterext */
     735             :     multibytecodec_methods,             /* tp_methods */
     736             : };
     737             : 
     738             : 
     739             : /**
     740             :  * Utility functions for stateful codec mechanism
     741             :  */
     742             : 
     743             : #define STATEFUL_DCTX(o)        ((MultibyteStatefulDecoderContext *)(o))
     744             : #define STATEFUL_ECTX(o)        ((MultibyteStatefulEncoderContext *)(o))
     745             : 
     746             : static PyObject *
     747           0 : encoder_encode_stateful(MultibyteStatefulEncoderContext *ctx,
     748             :                         PyObject *unistr, int final)
     749             : {
     750           0 :     PyObject *ucvt, *r = NULL;
     751           0 :     Py_UNICODE *inbuf, *inbuf_end, *inbuf_tmp = NULL;
     752             :     Py_ssize_t datalen, origpending;
     753             :     wchar_t *data;
     754             : 
     755           0 :     if (PyUnicode_Check(unistr))
     756           0 :         ucvt = NULL;
     757             :     else {
     758           0 :         unistr = ucvt = PyObject_Str(unistr);
     759           0 :         if (unistr == NULL)
     760           0 :             return NULL;
     761           0 :         else if (!PyUnicode_Check(unistr)) {
     762           0 :             PyErr_SetString(PyExc_TypeError,
     763             :                 "couldn't convert the object to unicode.");
     764           0 :             Py_DECREF(ucvt);
     765           0 :             return NULL;
     766             :         }
     767             :     }
     768             : 
     769           0 :     data = PyUnicode_AsUnicodeAndSize(unistr, &datalen);
     770           0 :     if (data == NULL)
     771           0 :         goto errorexit;
     772           0 :     origpending = ctx->pendingsize;
     773             : 
     774           0 :     if (origpending > 0) {
     775           0 :         if (datalen > PY_SSIZE_T_MAX - ctx->pendingsize) {
     776           0 :             PyErr_NoMemory();
     777             :             /* inbuf_tmp == NULL */
     778           0 :             goto errorexit;
     779             :         }
     780           0 :         inbuf_tmp = PyMem_New(Py_UNICODE, datalen + ctx->pendingsize);
     781           0 :         if (inbuf_tmp == NULL)
     782           0 :             goto errorexit;
     783           0 :         memcpy(inbuf_tmp, ctx->pending,
     784           0 :             Py_UNICODE_SIZE * ctx->pendingsize);
     785           0 :         memcpy(inbuf_tmp + ctx->pendingsize,
     786           0 :             PyUnicode_AS_UNICODE(unistr),
     787           0 :             Py_UNICODE_SIZE * datalen);
     788           0 :         datalen += ctx->pendingsize;
     789           0 :         ctx->pendingsize = 0;
     790           0 :         inbuf = inbuf_tmp;
     791             :     }
     792             :     else
     793           0 :         inbuf = (Py_UNICODE *)PyUnicode_AS_UNICODE(unistr);
     794             : 
     795           0 :     inbuf_end = inbuf + datalen;
     796             : 
     797           0 :     r = multibytecodec_encode(ctx->codec, &ctx->state,
     798             :                     (const Py_UNICODE **)&inbuf, datalen,
     799             :                     ctx->errors, final ? MBENC_FLUSH | MBENC_RESET : 0);
     800           0 :     if (r == NULL) {
     801             :         /* recover the original pending buffer */
     802           0 :         if (origpending > 0)
     803           0 :             memcpy(ctx->pending, inbuf_tmp,
     804           0 :                 Py_UNICODE_SIZE * origpending);
     805           0 :         ctx->pendingsize = origpending;
     806           0 :         goto errorexit;
     807             :     }
     808             : 
     809           0 :     if (inbuf < inbuf_end) {
     810           0 :         ctx->pendingsize = (Py_ssize_t)(inbuf_end - inbuf);
     811           0 :         if (ctx->pendingsize > MAXENCPENDING) {
     812             :             /* normal codecs can't reach here */
     813           0 :             ctx->pendingsize = 0;
     814           0 :             PyErr_SetString(PyExc_UnicodeError,
     815             :                             "pending buffer overflow");
     816           0 :             goto errorexit;
     817             :         }
     818           0 :         memcpy(ctx->pending, inbuf,
     819           0 :             ctx->pendingsize * Py_UNICODE_SIZE);
     820             :     }
     821             : 
     822           0 :     if (inbuf_tmp != NULL)
     823           0 :         PyMem_Del(inbuf_tmp);
     824           0 :     Py_XDECREF(ucvt);
     825           0 :     return r;
     826             : 
     827             : errorexit:
     828           0 :     if (inbuf_tmp != NULL)
     829           0 :         PyMem_Del(inbuf_tmp);
     830           0 :     Py_XDECREF(r);
     831           0 :     Py_XDECREF(ucvt);
     832           0 :     return NULL;
     833             : }
     834             : 
     835             : static int
     836           0 : decoder_append_pending(MultibyteStatefulDecoderContext *ctx,
     837             :                        MultibyteDecodeBuffer *buf)
     838             : {
     839             :     Py_ssize_t npendings;
     840             : 
     841           0 :     npendings = (Py_ssize_t)(buf->inbuf_end - buf->inbuf);
     842           0 :     if (npendings + ctx->pendingsize > MAXDECPENDING ||
     843           0 :         npendings > PY_SSIZE_T_MAX - ctx->pendingsize) {
     844           0 :             PyErr_SetString(PyExc_UnicodeError, "pending buffer overflow");
     845           0 :             return -1;
     846             :     }
     847           0 :     memcpy(ctx->pending + ctx->pendingsize, buf->inbuf, npendings);
     848           0 :     ctx->pendingsize += npendings;
     849           0 :     return 0;
     850             : }
     851             : 
     852             : static int
     853           0 : decoder_prepare_buffer(MultibyteDecodeBuffer *buf, const char *data,
     854             :                        Py_ssize_t size)
     855             : {
     856           0 :     buf->inbuf = buf->inbuf_top = (const unsigned char *)data;
     857           0 :     buf->inbuf_end = buf->inbuf_top + size;
     858           0 :     if (buf->outobj == NULL) { /* only if outobj is not allocated yet */
     859           0 :         buf->outobj = PyUnicode_FromUnicode(NULL, size);
     860           0 :         if (buf->outobj == NULL)
     861           0 :             return -1;
     862           0 :         buf->outbuf = PyUnicode_AsUnicode(buf->outobj);
     863           0 :         if (buf->outbuf == NULL)
     864           0 :             return -1;
     865           0 :         buf->outbuf_end = buf->outbuf +
     866           0 :                           PyUnicode_GET_SIZE(buf->outobj);
     867             :     }
     868             : 
     869           0 :     return 0;
     870             : }
     871             : 
     872             : static int
     873           0 : decoder_feed_buffer(MultibyteStatefulDecoderContext *ctx,
     874             :                     MultibyteDecodeBuffer *buf)
     875             : {
     876           0 :     while (buf->inbuf < buf->inbuf_end) {
     877             :         Py_ssize_t inleft, outleft;
     878             :         Py_ssize_t r;
     879             : 
     880           0 :         inleft = (Py_ssize_t)(buf->inbuf_end - buf->inbuf);
     881           0 :         outleft = (Py_ssize_t)(buf->outbuf_end - buf->outbuf);
     882             : 
     883           0 :         r = ctx->codec->decode(&ctx->state, ctx->codec->config,
     884             :             &buf->inbuf, inleft, &buf->outbuf, outleft);
     885           0 :         if (r == 0 || r == MBERR_TOOFEW)
     886             :             break;
     887           0 :         else if (multibytecodec_decerror(ctx->codec, &ctx->state,
     888             :                                          buf, ctx->errors, r))
     889           0 :             return -1;
     890             :     }
     891           0 :     return 0;
     892             : }
     893             : 
     894             : 
     895             : /**
     896             :  * MultibyteIncrementalEncoder object
     897             :  */
     898             : 
     899             : static PyObject *
     900           0 : mbiencoder_encode(MultibyteIncrementalEncoderObject *self,
     901             :                   PyObject *args, PyObject *kwargs)
     902             : {
     903             :     PyObject *data;
     904           0 :     int final = 0;
     905             : 
     906           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:encode",
     907             :                     incrementalkwarglist, &data, &final))
     908           0 :         return NULL;
     909             : 
     910           0 :     return encoder_encode_stateful(STATEFUL_ECTX(self), data, final);
     911             : }
     912             : 
     913             : static PyObject *
     914           0 : mbiencoder_reset(MultibyteIncrementalEncoderObject *self)
     915             : {
     916             :     /* Longest output: 4 bytes (b'\x0F\x1F(B') with ISO 2022 */
     917             :     unsigned char buffer[4], *outbuf;
     918             :     Py_ssize_t r;
     919           0 :     if (self->codec->encreset != NULL) {
     920           0 :         outbuf = buffer;
     921           0 :         r = self->codec->encreset(&self->state, self->codec->config,
     922             :                                   &outbuf, sizeof(buffer));
     923           0 :         if (r != 0)
     924           0 :             return NULL;
     925             :     }
     926           0 :     self->pendingsize = 0;
     927           0 :     Py_RETURN_NONE;
     928             : }
     929             : 
     930             : static struct PyMethodDef mbiencoder_methods[] = {
     931             :     {"encode",          (PyCFunction)mbiencoder_encode,
     932             :                     METH_VARARGS | METH_KEYWORDS, NULL},
     933             :     {"reset",           (PyCFunction)mbiencoder_reset,
     934             :                     METH_NOARGS, NULL},
     935             :     {NULL,              NULL},
     936             : };
     937             : 
     938             : static PyObject *
     939           0 : mbiencoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     940             : {
     941             :     MultibyteIncrementalEncoderObject *self;
     942           0 :     PyObject *codec = NULL;
     943           0 :     char *errors = NULL;
     944             : 
     945           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s:IncrementalEncoder",
     946             :                                      incnewkwarglist, &errors))
     947           0 :         return NULL;
     948             : 
     949           0 :     self = (MultibyteIncrementalEncoderObject *)type->tp_alloc(type, 0);
     950           0 :     if (self == NULL)
     951           0 :         return NULL;
     952             : 
     953           0 :     codec = PyObject_GetAttrString((PyObject *)type, "codec");
     954           0 :     if (codec == NULL)
     955           0 :         goto errorexit;
     956           0 :     if (!MultibyteCodec_Check(codec)) {
     957           0 :         PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
     958           0 :         goto errorexit;
     959             :     }
     960             : 
     961           0 :     self->codec = ((MultibyteCodecObject *)codec)->codec;
     962           0 :     self->pendingsize = 0;
     963           0 :     self->errors = internal_error_callback(errors);
     964           0 :     if (self->errors == NULL)
     965           0 :         goto errorexit;
     966           0 :     if (self->codec->encinit != NULL &&
     967           0 :         self->codec->encinit(&self->state, self->codec->config) != 0)
     968           0 :         goto errorexit;
     969             : 
     970           0 :     Py_DECREF(codec);
     971           0 :     return (PyObject *)self;
     972             : 
     973             : errorexit:
     974           0 :     Py_XDECREF(self);
     975           0 :     Py_XDECREF(codec);
     976           0 :     return NULL;
     977             : }
     978             : 
     979             : static int
     980           0 : mbiencoder_init(PyObject *self, PyObject *args, PyObject *kwds)
     981             : {
     982           0 :     return 0;
     983             : }
     984             : 
     985             : static int
     986           0 : mbiencoder_traverse(MultibyteIncrementalEncoderObject *self,
     987             :                     visitproc visit, void *arg)
     988             : {
     989           0 :     if (ERROR_ISCUSTOM(self->errors))
     990           0 :         Py_VISIT(self->errors);
     991           0 :     return 0;
     992             : }
     993             : 
     994             : static void
     995           0 : mbiencoder_dealloc(MultibyteIncrementalEncoderObject *self)
     996             : {
     997           0 :     PyObject_GC_UnTrack(self);
     998           0 :     ERROR_DECREF(self->errors);
     999           0 :     Py_TYPE(self)->tp_free(self);
    1000           0 : }
    1001             : 
    1002             : static PyTypeObject MultibyteIncrementalEncoder_Type = {
    1003             :     PyVarObject_HEAD_INIT(NULL, 0)
    1004             :     "MultibyteIncrementalEncoder",      /* tp_name */
    1005             :     sizeof(MultibyteIncrementalEncoderObject), /* tp_basicsize */
    1006             :     0,                                  /* tp_itemsize */
    1007             :     /*  methods  */
    1008             :     (destructor)mbiencoder_dealloc, /* tp_dealloc */
    1009             :     0,                                  /* tp_print */
    1010             :     0,                                  /* tp_getattr */
    1011             :     0,                                  /* tp_setattr */
    1012             :     0,                                  /* tp_reserved */
    1013             :     0,                                  /* tp_repr */
    1014             :     0,                                  /* tp_as_number */
    1015             :     0,                                  /* tp_as_sequence */
    1016             :     0,                                  /* tp_as_mapping */
    1017             :     0,                                  /* tp_hash */
    1018             :     0,                                  /* tp_call */
    1019             :     0,                                  /* tp_str */
    1020             :     PyObject_GenericGetAttr,            /* tp_getattro */
    1021             :     0,                                  /* tp_setattro */
    1022             :     0,                                  /* tp_as_buffer */
    1023             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
    1024             :         | Py_TPFLAGS_BASETYPE,          /* tp_flags */
    1025             :     0,                                  /* tp_doc */
    1026             :     (traverseproc)mbiencoder_traverse,          /* tp_traverse */
    1027             :     0,                                  /* tp_clear */
    1028             :     0,                                  /* tp_richcompare */
    1029             :     0,                                  /* tp_weaklistoffset */
    1030             :     0,                                  /* tp_iter */
    1031             :     0,                                  /* tp_iterext */
    1032             :     mbiencoder_methods,                 /* tp_methods */
    1033             :     0,                                  /* tp_members */
    1034             :     codecctx_getsets,                   /* tp_getset */
    1035             :     0,                                  /* tp_base */
    1036             :     0,                                  /* tp_dict */
    1037             :     0,                                  /* tp_descr_get */
    1038             :     0,                                  /* tp_descr_set */
    1039             :     0,                                  /* tp_dictoffset */
    1040             :     mbiencoder_init,                    /* tp_init */
    1041             :     0,                                  /* tp_alloc */
    1042             :     mbiencoder_new,                     /* tp_new */
    1043             : };
    1044             : 
    1045             : 
    1046             : /**
    1047             :  * MultibyteIncrementalDecoder object
    1048             :  */
    1049             : 
    1050             : static PyObject *
    1051           0 : mbidecoder_decode(MultibyteIncrementalDecoderObject *self,
    1052             :                   PyObject *args, PyObject *kwargs)
    1053             : {
    1054             :     MultibyteDecodeBuffer buf;
    1055           0 :     char *data, *wdata = NULL;
    1056             :     Py_buffer pdata;
    1057           0 :     Py_ssize_t wsize, finalsize = 0, size, origpending;
    1058           0 :     int final = 0;
    1059             : 
    1060           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|i:decode",
    1061             :                     incrementalkwarglist, &pdata, &final))
    1062           0 :         return NULL;
    1063           0 :     data = pdata.buf;
    1064           0 :     size = pdata.len;
    1065             : 
    1066           0 :     buf.outobj = buf.excobj = NULL;
    1067           0 :     origpending = self->pendingsize;
    1068             : 
    1069           0 :     if (self->pendingsize == 0) {
    1070           0 :         wsize = size;
    1071           0 :         wdata = data;
    1072             :     }
    1073             :     else {
    1074           0 :         if (size > PY_SSIZE_T_MAX - self->pendingsize) {
    1075           0 :             PyErr_NoMemory();
    1076           0 :             goto errorexit;
    1077             :         }
    1078           0 :         wsize = size + self->pendingsize;
    1079           0 :         wdata = PyMem_Malloc(wsize);
    1080           0 :         if (wdata == NULL)
    1081           0 :             goto errorexit;
    1082           0 :         memcpy(wdata, self->pending, self->pendingsize);
    1083           0 :         memcpy(wdata + self->pendingsize, data, size);
    1084           0 :         self->pendingsize = 0;
    1085             :     }
    1086             : 
    1087           0 :     if (decoder_prepare_buffer(&buf, wdata, wsize) != 0)
    1088           0 :         goto errorexit;
    1089             : 
    1090           0 :     if (decoder_feed_buffer(STATEFUL_DCTX(self), &buf))
    1091           0 :         goto errorexit;
    1092             : 
    1093           0 :     if (final && buf.inbuf < buf.inbuf_end) {
    1094           0 :         if (multibytecodec_decerror(self->codec, &self->state,
    1095             :                         &buf, self->errors, MBERR_TOOFEW)) {
    1096             :             /* recover the original pending buffer */
    1097           0 :             memcpy(self->pending, wdata, origpending);
    1098           0 :             self->pendingsize = origpending;
    1099           0 :             goto errorexit;
    1100             :         }
    1101             :     }
    1102             : 
    1103           0 :     if (buf.inbuf < buf.inbuf_end) { /* pending sequence still exists */
    1104           0 :         if (decoder_append_pending(STATEFUL_DCTX(self), &buf) != 0)
    1105           0 :             goto errorexit;
    1106             :     }
    1107             : 
    1108           0 :     finalsize = (Py_ssize_t)(buf.outbuf - PyUnicode_AS_UNICODE(buf.outobj));
    1109           0 :     if (finalsize != PyUnicode_GET_SIZE(buf.outobj))
    1110           0 :         if (PyUnicode_Resize(&buf.outobj, finalsize) == -1)
    1111           0 :             goto errorexit;
    1112             : 
    1113           0 :     PyBuffer_Release(&pdata);
    1114           0 :     if (wdata != data)
    1115           0 :         PyMem_Del(wdata);
    1116           0 :     Py_XDECREF(buf.excobj);
    1117           0 :     return buf.outobj;
    1118             : 
    1119             : errorexit:
    1120           0 :     PyBuffer_Release(&pdata);
    1121           0 :     if (wdata != NULL && wdata != data)
    1122           0 :         PyMem_Del(wdata);
    1123           0 :     Py_XDECREF(buf.excobj);
    1124           0 :     Py_XDECREF(buf.outobj);
    1125           0 :     return NULL;
    1126             : }
    1127             : 
    1128             : static PyObject *
    1129           0 : mbidecoder_reset(MultibyteIncrementalDecoderObject *self)
    1130             : {
    1131           0 :     if (self->codec->decreset != NULL &&
    1132           0 :         self->codec->decreset(&self->state, self->codec->config) != 0)
    1133           0 :         return NULL;
    1134           0 :     self->pendingsize = 0;
    1135             : 
    1136           0 :     Py_RETURN_NONE;
    1137             : }
    1138             : 
    1139             : static struct PyMethodDef mbidecoder_methods[] = {
    1140             :     {"decode",          (PyCFunction)mbidecoder_decode,
    1141             :                     METH_VARARGS | METH_KEYWORDS, NULL},
    1142             :     {"reset",           (PyCFunction)mbidecoder_reset,
    1143             :                     METH_NOARGS, NULL},
    1144             :     {NULL,              NULL},
    1145             : };
    1146             : 
    1147             : static PyObject *
    1148           0 : mbidecoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    1149             : {
    1150             :     MultibyteIncrementalDecoderObject *self;
    1151           0 :     PyObject *codec = NULL;
    1152           0 :     char *errors = NULL;
    1153             : 
    1154           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s:IncrementalDecoder",
    1155             :                                      incnewkwarglist, &errors))
    1156           0 :         return NULL;
    1157             : 
    1158           0 :     self = (MultibyteIncrementalDecoderObject *)type->tp_alloc(type, 0);
    1159           0 :     if (self == NULL)
    1160           0 :         return NULL;
    1161             : 
    1162           0 :     codec = PyObject_GetAttrString((PyObject *)type, "codec");
    1163           0 :     if (codec == NULL)
    1164           0 :         goto errorexit;
    1165           0 :     if (!MultibyteCodec_Check(codec)) {
    1166           0 :         PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
    1167           0 :         goto errorexit;
    1168             :     }
    1169             : 
    1170           0 :     self->codec = ((MultibyteCodecObject *)codec)->codec;
    1171           0 :     self->pendingsize = 0;
    1172           0 :     self->errors = internal_error_callback(errors);
    1173           0 :     if (self->errors == NULL)
    1174           0 :         goto errorexit;
    1175           0 :     if (self->codec->decinit != NULL &&
    1176           0 :         self->codec->decinit(&self->state, self->codec->config) != 0)
    1177           0 :         goto errorexit;
    1178             : 
    1179           0 :     Py_DECREF(codec);
    1180           0 :     return (PyObject *)self;
    1181             : 
    1182             : errorexit:
    1183           0 :     Py_XDECREF(self);
    1184           0 :     Py_XDECREF(codec);
    1185           0 :     return NULL;
    1186             : }
    1187             : 
    1188             : static int
    1189           0 : mbidecoder_init(PyObject *self, PyObject *args, PyObject *kwds)
    1190             : {
    1191           0 :     return 0;
    1192             : }
    1193             : 
    1194             : static int
    1195           0 : mbidecoder_traverse(MultibyteIncrementalDecoderObject *self,
    1196             :                     visitproc visit, void *arg)
    1197             : {
    1198           0 :     if (ERROR_ISCUSTOM(self->errors))
    1199           0 :         Py_VISIT(self->errors);
    1200           0 :     return 0;
    1201             : }
    1202             : 
    1203             : static void
    1204           0 : mbidecoder_dealloc(MultibyteIncrementalDecoderObject *self)
    1205             : {
    1206           0 :     PyObject_GC_UnTrack(self);
    1207           0 :     ERROR_DECREF(self->errors);
    1208           0 :     Py_TYPE(self)->tp_free(self);
    1209           0 : }
    1210             : 
    1211             : static PyTypeObject MultibyteIncrementalDecoder_Type = {
    1212             :     PyVarObject_HEAD_INIT(NULL, 0)
    1213             :     "MultibyteIncrementalDecoder",      /* tp_name */
    1214             :     sizeof(MultibyteIncrementalDecoderObject), /* tp_basicsize */
    1215             :     0,                                  /* tp_itemsize */
    1216             :     /*  methods  */
    1217             :     (destructor)mbidecoder_dealloc, /* tp_dealloc */
    1218             :     0,                                  /* tp_print */
    1219             :     0,                                  /* tp_getattr */
    1220             :     0,                                  /* tp_setattr */
    1221             :     0,                                  /* tp_reserved */
    1222             :     0,                                  /* tp_repr */
    1223             :     0,                                  /* tp_as_number */
    1224             :     0,                                  /* tp_as_sequence */
    1225             :     0,                                  /* tp_as_mapping */
    1226             :     0,                                  /* tp_hash */
    1227             :     0,                                  /* tp_call */
    1228             :     0,                                  /* tp_str */
    1229             :     PyObject_GenericGetAttr,            /* tp_getattro */
    1230             :     0,                                  /* tp_setattro */
    1231             :     0,                                  /* tp_as_buffer */
    1232             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
    1233             :         | Py_TPFLAGS_BASETYPE,          /* tp_flags */
    1234             :     0,                                  /* tp_doc */
    1235             :     (traverseproc)mbidecoder_traverse,          /* tp_traverse */
    1236             :     0,                                  /* tp_clear */
    1237             :     0,                                  /* tp_richcompare */
    1238             :     0,                                  /* tp_weaklistoffset */
    1239             :     0,                                  /* tp_iter */
    1240             :     0,                                  /* tp_iterext */
    1241             :     mbidecoder_methods,                 /* tp_methods */
    1242             :     0,                                  /* tp_members */
    1243             :     codecctx_getsets,                   /* tp_getset */
    1244             :     0,                                  /* tp_base */
    1245             :     0,                                  /* tp_dict */
    1246             :     0,                                  /* tp_descr_get */
    1247             :     0,                                  /* tp_descr_set */
    1248             :     0,                                  /* tp_dictoffset */
    1249             :     mbidecoder_init,                    /* tp_init */
    1250             :     0,                                  /* tp_alloc */
    1251             :     mbidecoder_new,                     /* tp_new */
    1252             : };
    1253             : 
    1254             : 
    1255             : /**
    1256             :  * MultibyteStreamReader object
    1257             :  */
    1258             : 
    1259             : static PyObject *
    1260           0 : mbstreamreader_iread(MultibyteStreamReaderObject *self,
    1261             :                      const char *method, Py_ssize_t sizehint)
    1262             : {
    1263             :     MultibyteDecodeBuffer buf;
    1264             :     PyObject *cres;
    1265           0 :     Py_ssize_t rsize, finalsize = 0;
    1266             : 
    1267           0 :     if (sizehint == 0)
    1268           0 :         return PyUnicode_New(0, 0);
    1269             : 
    1270           0 :     buf.outobj = buf.excobj = NULL;
    1271           0 :     cres = NULL;
    1272             : 
    1273             :     for (;;) {
    1274             :         int endoffile;
    1275             : 
    1276           0 :         if (sizehint < 0)
    1277           0 :             cres = PyObject_CallMethod(self->stream,
    1278             :                             (char *)method, NULL);
    1279             :         else
    1280           0 :             cres = PyObject_CallMethod(self->stream,
    1281             :                             (char *)method, "i", sizehint);
    1282           0 :         if (cres == NULL)
    1283           0 :             goto errorexit;
    1284             : 
    1285           0 :         if (!PyBytes_Check(cres)) {
    1286           0 :             PyErr_Format(PyExc_TypeError,
    1287             :                          "stream function returned a "
    1288             :                          "non-bytes object (%.100s)",
    1289           0 :                          cres->ob_type->tp_name);
    1290           0 :             goto errorexit;
    1291             :         }
    1292             : 
    1293           0 :         endoffile = (PyBytes_GET_SIZE(cres) == 0);
    1294             : 
    1295           0 :         if (self->pendingsize > 0) {
    1296             :             PyObject *ctr;
    1297             :             char *ctrdata;
    1298             : 
    1299           0 :             if (PyBytes_GET_SIZE(cres) > PY_SSIZE_T_MAX - self->pendingsize) {
    1300           0 :                 PyErr_NoMemory();
    1301           0 :                 goto errorexit;
    1302             :         }
    1303           0 :                     rsize = PyBytes_GET_SIZE(cres) + self->pendingsize;
    1304           0 :                     ctr = PyBytes_FromStringAndSize(NULL, rsize);
    1305           0 :                     if (ctr == NULL)
    1306           0 :                             goto errorexit;
    1307           0 :                     ctrdata = PyBytes_AS_STRING(ctr);
    1308           0 :                     memcpy(ctrdata, self->pending, self->pendingsize);
    1309           0 :                     memcpy(ctrdata + self->pendingsize,
    1310           0 :                             PyBytes_AS_STRING(cres),
    1311           0 :                             PyBytes_GET_SIZE(cres));
    1312           0 :                     Py_DECREF(cres);
    1313           0 :                     cres = ctr;
    1314           0 :                     self->pendingsize = 0;
    1315             :         }
    1316             : 
    1317           0 :         rsize = PyBytes_GET_SIZE(cres);
    1318           0 :         if (decoder_prepare_buffer(&buf, PyBytes_AS_STRING(cres),
    1319             :                                    rsize) != 0)
    1320           0 :             goto errorexit;
    1321             : 
    1322           0 :         if (rsize > 0 && decoder_feed_buffer(
    1323             :                         (MultibyteStatefulDecoderContext *)self, &buf))
    1324           0 :             goto errorexit;
    1325             : 
    1326           0 :         if (endoffile || sizehint < 0) {
    1327           0 :             if (buf.inbuf < buf.inbuf_end &&
    1328           0 :                 multibytecodec_decerror(self->codec, &self->state,
    1329             :                             &buf, self->errors, MBERR_TOOFEW))
    1330           0 :                 goto errorexit;
    1331             :         }
    1332             : 
    1333           0 :         if (buf.inbuf < buf.inbuf_end) { /* pending sequence exists */
    1334           0 :             if (decoder_append_pending(STATEFUL_DCTX(self),
    1335             :                                        &buf) != 0)
    1336           0 :                 goto errorexit;
    1337             :         }
    1338             : 
    1339           0 :         finalsize = (Py_ssize_t)(buf.outbuf -
    1340           0 :                         PyUnicode_AS_UNICODE(buf.outobj));
    1341           0 :         Py_DECREF(cres);
    1342           0 :         cres = NULL;
    1343             : 
    1344           0 :         if (sizehint < 0 || finalsize != 0 || rsize == 0)
    1345             :             break;
    1346             : 
    1347           0 :         sizehint = 1; /* read 1 more byte and retry */
    1348           0 :     }
    1349             : 
    1350           0 :     if (finalsize != PyUnicode_GET_SIZE(buf.outobj))
    1351           0 :         if (PyUnicode_Resize(&buf.outobj, finalsize) == -1)
    1352           0 :             goto errorexit;
    1353             : 
    1354           0 :     Py_XDECREF(cres);
    1355           0 :     Py_XDECREF(buf.excobj);
    1356           0 :     return buf.outobj;
    1357             : 
    1358             : errorexit:
    1359           0 :     Py_XDECREF(cres);
    1360           0 :     Py_XDECREF(buf.excobj);
    1361           0 :     Py_XDECREF(buf.outobj);
    1362           0 :     return NULL;
    1363             : }
    1364             : 
    1365             : static PyObject *
    1366           0 : mbstreamreader_read(MultibyteStreamReaderObject *self, PyObject *args)
    1367             : {
    1368           0 :     PyObject *sizeobj = NULL;
    1369             :     Py_ssize_t size;
    1370             : 
    1371           0 :     if (!PyArg_UnpackTuple(args, "read", 0, 1, &sizeobj))
    1372           0 :         return NULL;
    1373             : 
    1374           0 :     if (sizeobj == Py_None || sizeobj == NULL)
    1375           0 :         size = -1;
    1376           0 :     else if (PyLong_Check(sizeobj))
    1377           0 :         size = PyLong_AsSsize_t(sizeobj);
    1378             :     else {
    1379           0 :         PyErr_SetString(PyExc_TypeError, "arg 1 must be an integer");
    1380           0 :         return NULL;
    1381             :     }
    1382             : 
    1383           0 :     if (size == -1 && PyErr_Occurred())
    1384           0 :         return NULL;
    1385             : 
    1386           0 :     return mbstreamreader_iread(self, "read", size);
    1387             : }
    1388             : 
    1389             : static PyObject *
    1390           0 : mbstreamreader_readline(MultibyteStreamReaderObject *self, PyObject *args)
    1391             : {
    1392           0 :     PyObject *sizeobj = NULL;
    1393             :     Py_ssize_t size;
    1394             : 
    1395           0 :     if (!PyArg_UnpackTuple(args, "readline", 0, 1, &sizeobj))
    1396           0 :         return NULL;
    1397             : 
    1398           0 :     if (sizeobj == Py_None || sizeobj == NULL)
    1399           0 :         size = -1;
    1400           0 :     else if (PyLong_Check(sizeobj))
    1401           0 :         size = PyLong_AsSsize_t(sizeobj);
    1402             :     else {
    1403           0 :         PyErr_SetString(PyExc_TypeError, "arg 1 must be an integer");
    1404           0 :         return NULL;
    1405             :     }
    1406             : 
    1407           0 :     if (size == -1 && PyErr_Occurred())
    1408           0 :         return NULL;
    1409             : 
    1410           0 :     return mbstreamreader_iread(self, "readline", size);
    1411             : }
    1412             : 
    1413             : static PyObject *
    1414           0 : mbstreamreader_readlines(MultibyteStreamReaderObject *self, PyObject *args)
    1415             : {
    1416           0 :     PyObject *sizehintobj = NULL, *r, *sr;
    1417             :     Py_ssize_t sizehint;
    1418             : 
    1419           0 :     if (!PyArg_UnpackTuple(args, "readlines", 0, 1, &sizehintobj))
    1420           0 :         return NULL;
    1421             : 
    1422           0 :     if (sizehintobj == Py_None || sizehintobj == NULL)
    1423           0 :         sizehint = -1;
    1424           0 :     else if (PyLong_Check(sizehintobj))
    1425           0 :         sizehint = PyLong_AsSsize_t(sizehintobj);
    1426             :     else {
    1427           0 :         PyErr_SetString(PyExc_TypeError, "arg 1 must be an integer");
    1428           0 :         return NULL;
    1429             :     }
    1430             : 
    1431           0 :     if (sizehint == -1 && PyErr_Occurred())
    1432           0 :         return NULL;
    1433             : 
    1434           0 :     r = mbstreamreader_iread(self, "read", sizehint);
    1435           0 :     if (r == NULL)
    1436           0 :         return NULL;
    1437             : 
    1438           0 :     sr = PyUnicode_Splitlines(r, 1);
    1439           0 :     Py_DECREF(r);
    1440           0 :     return sr;
    1441             : }
    1442             : 
    1443             : static PyObject *
    1444           0 : mbstreamreader_reset(MultibyteStreamReaderObject *self)
    1445             : {
    1446           0 :     if (self->codec->decreset != NULL &&
    1447           0 :         self->codec->decreset(&self->state, self->codec->config) != 0)
    1448           0 :         return NULL;
    1449           0 :     self->pendingsize = 0;
    1450             : 
    1451           0 :     Py_RETURN_NONE;
    1452             : }
    1453             : 
    1454             : static struct PyMethodDef mbstreamreader_methods[] = {
    1455             :     {"read",            (PyCFunction)mbstreamreader_read,
    1456             :                     METH_VARARGS, NULL},
    1457             :     {"readline",        (PyCFunction)mbstreamreader_readline,
    1458             :                     METH_VARARGS, NULL},
    1459             :     {"readlines",       (PyCFunction)mbstreamreader_readlines,
    1460             :                     METH_VARARGS, NULL},
    1461             :     {"reset",           (PyCFunction)mbstreamreader_reset,
    1462             :                     METH_NOARGS, NULL},
    1463             :     {NULL,              NULL},
    1464             : };
    1465             : 
    1466             : static PyMemberDef mbstreamreader_members[] = {
    1467             :     {"stream",          T_OBJECT,
    1468             :                     offsetof(MultibyteStreamReaderObject, stream),
    1469             :                     READONLY, NULL},
    1470             :     {NULL,}
    1471             : };
    1472             : 
    1473             : static PyObject *
    1474           0 : mbstreamreader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    1475             : {
    1476             :     MultibyteStreamReaderObject *self;
    1477           0 :     PyObject *stream, *codec = NULL;
    1478           0 :     char *errors = NULL;
    1479             : 
    1480           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s:StreamReader",
    1481             :                             streamkwarglist, &stream, &errors))
    1482           0 :         return NULL;
    1483             : 
    1484           0 :     self = (MultibyteStreamReaderObject *)type->tp_alloc(type, 0);
    1485           0 :     if (self == NULL)
    1486           0 :         return NULL;
    1487             : 
    1488           0 :     codec = PyObject_GetAttrString((PyObject *)type, "codec");
    1489           0 :     if (codec == NULL)
    1490           0 :         goto errorexit;
    1491           0 :     if (!MultibyteCodec_Check(codec)) {
    1492           0 :         PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
    1493           0 :         goto errorexit;
    1494             :     }
    1495             : 
    1496           0 :     self->codec = ((MultibyteCodecObject *)codec)->codec;
    1497           0 :     self->stream = stream;
    1498           0 :     Py_INCREF(stream);
    1499           0 :     self->pendingsize = 0;
    1500           0 :     self->errors = internal_error_callback(errors);
    1501           0 :     if (self->errors == NULL)
    1502           0 :         goto errorexit;
    1503           0 :     if (self->codec->decinit != NULL &&
    1504           0 :         self->codec->decinit(&self->state, self->codec->config) != 0)
    1505           0 :         goto errorexit;
    1506             : 
    1507           0 :     Py_DECREF(codec);
    1508           0 :     return (PyObject *)self;
    1509             : 
    1510             : errorexit:
    1511           0 :     Py_XDECREF(self);
    1512           0 :     Py_XDECREF(codec);
    1513           0 :     return NULL;
    1514             : }
    1515             : 
    1516             : static int
    1517           0 : mbstreamreader_init(PyObject *self, PyObject *args, PyObject *kwds)
    1518             : {
    1519           0 :     return 0;
    1520             : }
    1521             : 
    1522             : static int
    1523           0 : mbstreamreader_traverse(MultibyteStreamReaderObject *self,
    1524             :                         visitproc visit, void *arg)
    1525             : {
    1526           0 :     if (ERROR_ISCUSTOM(self->errors))
    1527           0 :         Py_VISIT(self->errors);
    1528           0 :     Py_VISIT(self->stream);
    1529           0 :     return 0;
    1530             : }
    1531             : 
    1532             : static void
    1533           0 : mbstreamreader_dealloc(MultibyteStreamReaderObject *self)
    1534             : {
    1535           0 :     PyObject_GC_UnTrack(self);
    1536           0 :     ERROR_DECREF(self->errors);
    1537           0 :     Py_XDECREF(self->stream);
    1538           0 :     Py_TYPE(self)->tp_free(self);
    1539           0 : }
    1540             : 
    1541             : static PyTypeObject MultibyteStreamReader_Type = {
    1542             :     PyVarObject_HEAD_INIT(NULL, 0)
    1543             :     "MultibyteStreamReader",            /* tp_name */
    1544             :     sizeof(MultibyteStreamReaderObject), /* tp_basicsize */
    1545             :     0,                                  /* tp_itemsize */
    1546             :     /*  methods  */
    1547             :     (destructor)mbstreamreader_dealloc, /* tp_dealloc */
    1548             :     0,                                  /* tp_print */
    1549             :     0,                                  /* tp_getattr */
    1550             :     0,                                  /* tp_setattr */
    1551             :     0,                                  /* tp_reserved */
    1552             :     0,                                  /* tp_repr */
    1553             :     0,                                  /* tp_as_number */
    1554             :     0,                                  /* tp_as_sequence */
    1555             :     0,                                  /* tp_as_mapping */
    1556             :     0,                                  /* tp_hash */
    1557             :     0,                                  /* tp_call */
    1558             :     0,                                  /* tp_str */
    1559             :     PyObject_GenericGetAttr,            /* tp_getattro */
    1560             :     0,                                  /* tp_setattro */
    1561             :     0,                                  /* tp_as_buffer */
    1562             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
    1563             :         | Py_TPFLAGS_BASETYPE,          /* tp_flags */
    1564             :     0,                                  /* tp_doc */
    1565             :     (traverseproc)mbstreamreader_traverse,      /* tp_traverse */
    1566             :     0,                                  /* tp_clear */
    1567             :     0,                                  /* tp_richcompare */
    1568             :     0,                                  /* tp_weaklistoffset */
    1569             :     0,                                  /* tp_iter */
    1570             :     0,                                  /* tp_iterext */
    1571             :     mbstreamreader_methods,             /* tp_methods */
    1572             :     mbstreamreader_members,             /* tp_members */
    1573             :     codecctx_getsets,                   /* tp_getset */
    1574             :     0,                                  /* tp_base */
    1575             :     0,                                  /* tp_dict */
    1576             :     0,                                  /* tp_descr_get */
    1577             :     0,                                  /* tp_descr_set */
    1578             :     0,                                  /* tp_dictoffset */
    1579             :     mbstreamreader_init,                /* tp_init */
    1580             :     0,                                  /* tp_alloc */
    1581             :     mbstreamreader_new,                 /* tp_new */
    1582             : };
    1583             : 
    1584             : 
    1585             : /**
    1586             :  * MultibyteStreamWriter object
    1587             :  */
    1588             : 
    1589             : static int
    1590           0 : mbstreamwriter_iwrite(MultibyteStreamWriterObject *self,
    1591             :                       PyObject *unistr)
    1592             : {
    1593             :     PyObject *str, *wr;
    1594             :     _Py_IDENTIFIER(write);
    1595             : 
    1596           0 :     str = encoder_encode_stateful(STATEFUL_ECTX(self), unistr, 0);
    1597           0 :     if (str == NULL)
    1598           0 :         return -1;
    1599             : 
    1600           0 :     wr = _PyObject_CallMethodId(self->stream, &PyId_write, "O", str);
    1601           0 :     Py_DECREF(str);
    1602           0 :     if (wr == NULL)
    1603           0 :         return -1;
    1604             : 
    1605           0 :     Py_DECREF(wr);
    1606           0 :     return 0;
    1607             : }
    1608             : 
    1609             : static PyObject *
    1610           0 : mbstreamwriter_write(MultibyteStreamWriterObject *self, PyObject *strobj)
    1611             : {
    1612           0 :     if (mbstreamwriter_iwrite(self, strobj))
    1613           0 :         return NULL;
    1614             :     else
    1615           0 :         Py_RETURN_NONE;
    1616             : }
    1617             : 
    1618             : static PyObject *
    1619           0 : mbstreamwriter_writelines(MultibyteStreamWriterObject *self, PyObject *lines)
    1620             : {
    1621             :     PyObject *strobj;
    1622             :     int i, r;
    1623             : 
    1624           0 :     if (!PySequence_Check(lines)) {
    1625           0 :         PyErr_SetString(PyExc_TypeError,
    1626             :                         "arg must be a sequence object");
    1627           0 :         return NULL;
    1628             :     }
    1629             : 
    1630           0 :     for (i = 0; i < PySequence_Length(lines); i++) {
    1631             :         /* length can be changed even within this loop */
    1632           0 :         strobj = PySequence_GetItem(lines, i);
    1633           0 :         if (strobj == NULL)
    1634           0 :             return NULL;
    1635             : 
    1636           0 :         r = mbstreamwriter_iwrite(self, strobj);
    1637           0 :         Py_DECREF(strobj);
    1638           0 :         if (r == -1)
    1639           0 :             return NULL;
    1640             :     }
    1641             : 
    1642           0 :     Py_RETURN_NONE;
    1643             : }
    1644             : 
    1645             : static PyObject *
    1646           0 : mbstreamwriter_reset(MultibyteStreamWriterObject *self)
    1647             : {
    1648             :     const Py_UNICODE *pending;
    1649             :     PyObject *pwrt;
    1650             : 
    1651           0 :     pending = self->pending;
    1652           0 :     pwrt = multibytecodec_encode(self->codec, &self->state,
    1653             :                     &pending, self->pendingsize, self->errors,
    1654             :                     MBENC_FLUSH | MBENC_RESET);
    1655             :     /* some pending buffer can be truncated when UnicodeEncodeError is
    1656             :      * raised on 'strict' mode. but, 'reset' method is designed to
    1657             :      * reset the pending buffer or states so failed string sequence
    1658             :      * ought to be missed */
    1659           0 :     self->pendingsize = 0;
    1660           0 :     if (pwrt == NULL)
    1661           0 :         return NULL;
    1662             : 
    1663             :     assert(PyBytes_Check(pwrt));
    1664           0 :     if (PyBytes_Size(pwrt) > 0) {
    1665             :         PyObject *wr;
    1666             :         _Py_IDENTIFIER(write);
    1667             : 
    1668           0 :         wr = _PyObject_CallMethodId(self->stream, &PyId_write, "O", pwrt);
    1669           0 :         if (wr == NULL) {
    1670           0 :             Py_DECREF(pwrt);
    1671           0 :             return NULL;
    1672             :         }
    1673             :     }
    1674           0 :     Py_DECREF(pwrt);
    1675             : 
    1676           0 :     Py_RETURN_NONE;
    1677             : }
    1678             : 
    1679             : static PyObject *
    1680           0 : mbstreamwriter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    1681             : {
    1682             :     MultibyteStreamWriterObject *self;
    1683           0 :     PyObject *stream, *codec = NULL;
    1684           0 :     char *errors = NULL;
    1685             : 
    1686           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s:StreamWriter",
    1687             :                             streamkwarglist, &stream, &errors))
    1688           0 :         return NULL;
    1689             : 
    1690           0 :     self = (MultibyteStreamWriterObject *)type->tp_alloc(type, 0);
    1691           0 :     if (self == NULL)
    1692           0 :         return NULL;
    1693             : 
    1694           0 :     codec = PyObject_GetAttrString((PyObject *)type, "codec");
    1695           0 :     if (codec == NULL)
    1696           0 :         goto errorexit;
    1697           0 :     if (!MultibyteCodec_Check(codec)) {
    1698           0 :         PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
    1699           0 :         goto errorexit;
    1700             :     }
    1701             : 
    1702           0 :     self->codec = ((MultibyteCodecObject *)codec)->codec;
    1703           0 :     self->stream = stream;
    1704           0 :     Py_INCREF(stream);
    1705           0 :     self->pendingsize = 0;
    1706           0 :     self->errors = internal_error_callback(errors);
    1707           0 :     if (self->errors == NULL)
    1708           0 :         goto errorexit;
    1709           0 :     if (self->codec->encinit != NULL &&
    1710           0 :         self->codec->encinit(&self->state, self->codec->config) != 0)
    1711           0 :         goto errorexit;
    1712             : 
    1713           0 :     Py_DECREF(codec);
    1714           0 :     return (PyObject *)self;
    1715             : 
    1716             : errorexit:
    1717           0 :     Py_XDECREF(self);
    1718           0 :     Py_XDECREF(codec);
    1719           0 :     return NULL;
    1720             : }
    1721             : 
    1722             : static int
    1723           0 : mbstreamwriter_init(PyObject *self, PyObject *args, PyObject *kwds)
    1724             : {
    1725           0 :     return 0;
    1726             : }
    1727             : 
    1728             : static int
    1729           0 : mbstreamwriter_traverse(MultibyteStreamWriterObject *self,
    1730             :                         visitproc visit, void *arg)
    1731             : {
    1732           0 :     if (ERROR_ISCUSTOM(self->errors))
    1733           0 :         Py_VISIT(self->errors);
    1734           0 :     Py_VISIT(self->stream);
    1735           0 :     return 0;
    1736             : }
    1737             : 
    1738             : static void
    1739           0 : mbstreamwriter_dealloc(MultibyteStreamWriterObject *self)
    1740             : {
    1741           0 :     PyObject_GC_UnTrack(self);
    1742           0 :     ERROR_DECREF(self->errors);
    1743           0 :     Py_XDECREF(self->stream);
    1744           0 :     Py_TYPE(self)->tp_free(self);
    1745           0 : }
    1746             : 
    1747             : static struct PyMethodDef mbstreamwriter_methods[] = {
    1748             :     {"write",           (PyCFunction)mbstreamwriter_write,
    1749             :                     METH_O, NULL},
    1750             :     {"writelines",      (PyCFunction)mbstreamwriter_writelines,
    1751             :                     METH_O, NULL},
    1752             :     {"reset",           (PyCFunction)mbstreamwriter_reset,
    1753             :                     METH_NOARGS, NULL},
    1754             :     {NULL,              NULL},
    1755             : };
    1756             : 
    1757             : static PyMemberDef mbstreamwriter_members[] = {
    1758             :     {"stream",          T_OBJECT,
    1759             :                     offsetof(MultibyteStreamWriterObject, stream),
    1760             :                     READONLY, NULL},
    1761             :     {NULL,}
    1762             : };
    1763             : 
    1764             : static PyTypeObject MultibyteStreamWriter_Type = {
    1765             :     PyVarObject_HEAD_INIT(NULL, 0)
    1766             :     "MultibyteStreamWriter",            /* tp_name */
    1767             :     sizeof(MultibyteStreamWriterObject), /* tp_basicsize */
    1768             :     0,                                  /* tp_itemsize */
    1769             :     /*  methods  */
    1770             :     (destructor)mbstreamwriter_dealloc, /* tp_dealloc */
    1771             :     0,                                  /* tp_print */
    1772             :     0,                                  /* tp_getattr */
    1773             :     0,                                  /* tp_setattr */
    1774             :     0,                                  /* tp_reserved */
    1775             :     0,                                  /* tp_repr */
    1776             :     0,                                  /* tp_as_number */
    1777             :     0,                                  /* tp_as_sequence */
    1778             :     0,                                  /* tp_as_mapping */
    1779             :     0,                                  /* tp_hash */
    1780             :     0,                                  /* tp_call */
    1781             :     0,                                  /* tp_str */
    1782             :     PyObject_GenericGetAttr,            /* tp_getattro */
    1783             :     0,                                  /* tp_setattro */
    1784             :     0,                                  /* tp_as_buffer */
    1785             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
    1786             :         | Py_TPFLAGS_BASETYPE,          /* tp_flags */
    1787             :     0,                                  /* tp_doc */
    1788             :     (traverseproc)mbstreamwriter_traverse,      /* tp_traverse */
    1789             :     0,                                  /* tp_clear */
    1790             :     0,                                  /* tp_richcompare */
    1791             :     0,                                  /* tp_weaklistoffset */
    1792             :     0,                                  /* tp_iter */
    1793             :     0,                                  /* tp_iterext */
    1794             :     mbstreamwriter_methods,             /* tp_methods */
    1795             :     mbstreamwriter_members,             /* tp_members */
    1796             :     codecctx_getsets,                   /* tp_getset */
    1797             :     0,                                  /* tp_base */
    1798             :     0,                                  /* tp_dict */
    1799             :     0,                                  /* tp_descr_get */
    1800             :     0,                                  /* tp_descr_set */
    1801             :     0,                                  /* tp_dictoffset */
    1802             :     mbstreamwriter_init,                /* tp_init */
    1803             :     0,                                  /* tp_alloc */
    1804             :     mbstreamwriter_new,                 /* tp_new */
    1805             : };
    1806             : 
    1807             : 
    1808             : /**
    1809             :  * Exposed factory function
    1810             :  */
    1811             : 
    1812             : static PyObject *
    1813           0 : __create_codec(PyObject *ignore, PyObject *arg)
    1814             : {
    1815             :     MultibyteCodecObject *self;
    1816             :     MultibyteCodec *codec;
    1817             : 
    1818           0 :     if (!PyCapsule_IsValid(arg, PyMultibyteCodec_CAPSULE_NAME)) {
    1819           0 :         PyErr_SetString(PyExc_ValueError, "argument type invalid");
    1820           0 :         return NULL;
    1821             :     }
    1822             : 
    1823           0 :     codec = PyCapsule_GetPointer(arg, PyMultibyteCodec_CAPSULE_NAME);
    1824           0 :     if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0)
    1825           0 :         return NULL;
    1826             : 
    1827           0 :     self = PyObject_New(MultibyteCodecObject, &MultibyteCodec_Type);
    1828           0 :     if (self == NULL)
    1829           0 :         return NULL;
    1830           0 :     self->codec = codec;
    1831             : 
    1832           0 :     return (PyObject *)self;
    1833             : }
    1834             : 
    1835             : static struct PyMethodDef __methods[] = {
    1836             :     {"__create_codec", (PyCFunction)__create_codec, METH_O},
    1837             :     {NULL, NULL},
    1838             : };
    1839             : 
    1840             : 
    1841             : static struct PyModuleDef _multibytecodecmodule = {
    1842             :     PyModuleDef_HEAD_INIT,
    1843             :     "_multibytecodec",
    1844             :     NULL,
    1845             :     -1,
    1846             :     __methods,
    1847             :     NULL,
    1848             :     NULL,
    1849             :     NULL,
    1850             :     NULL
    1851             : };
    1852             : 
    1853             : PyMODINIT_FUNC
    1854           0 : PyInit__multibytecodec(void)
    1855             : {
    1856             :     int i;
    1857             :     PyObject *m;
    1858           0 :     PyTypeObject *typelist[] = {
    1859             :         &MultibyteIncrementalEncoder_Type,
    1860             :         &MultibyteIncrementalDecoder_Type,
    1861             :         &MultibyteStreamReader_Type,
    1862             :         &MultibyteStreamWriter_Type,
    1863             :         NULL
    1864             :     };
    1865             : 
    1866           0 :     if (PyType_Ready(&MultibyteCodec_Type) < 0)
    1867           0 :         return NULL;
    1868             : 
    1869           0 :     m = PyModule_Create(&_multibytecodecmodule);
    1870           0 :     if (m == NULL)
    1871           0 :         return NULL;
    1872             : 
    1873           0 :     for (i = 0; typelist[i] != NULL; i++) {
    1874           0 :         if (PyType_Ready(typelist[i]) < 0)
    1875           0 :             return NULL;
    1876           0 :         Py_INCREF(typelist[i]);
    1877           0 :         PyModule_AddObject(m, typelist[i]->tp_name,
    1878           0 :                            (PyObject *)typelist[i]);
    1879             :     }
    1880             : 
    1881           0 :     if (PyErr_Occurred()) {
    1882           0 :         Py_FatalError("can't initialize the _multibytecodec module");
    1883           0 :         Py_DECREF(m);
    1884           0 :         m = NULL;
    1885             :     }
    1886           0 :     return m;
    1887             : }

Generated by: LCOV version 1.10