LCOV - code coverage report
Current view: top level - Modules/cjkcodecs - multibytecodec.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit 5e6661bce9] Lines: 39 918 4.2 %
Date: 2023-03-20 08:15:36 Functions: 6 58 10.3 %
Branches: 32 641 5.0 %

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

Generated by: LCOV version 1.14