LCOV - code coverage report
Current view: top level - Modules/cjkcodecs - multibytecodec.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 689 923 74.6 %
Date: 2022-07-20 13:12:14 Functions: 54 58 93.1 %
Branches: 375 643 58.3 %

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

Generated by: LCOV version 1.14