@@ -32,16 +32,45 @@ Copyright (c) Corporation for National Research Initiatives.
3232
3333#include "Python.h"
3434#include "pycore_codecs.h" // _PyCodec_Lookup()
35+ #include "pycore_pymem.h" // _PyMem_Strdup()
3536#include "pycore_unicodeobject.h" // _PyUnicode_EncodeCharmap
3637
3738#ifdef MS_WINDOWS
3839#include <windows.h>
3940#endif
4041
42+ typedef struct {
43+ PyTypeObject * IconvDecoderType ;
44+ } _codecs_state ;
45+
46+ static inline _codecs_state *
47+ get_codecs_state (PyObject * module )
48+ {
49+ void * state = PyModule_GetState (module );
50+ assert (state != NULL );
51+ return (_codecs_state * )state ;
52+ }
53+
54+ static struct PyModuleDef codecsmodule ;
55+
56+ #define get_codecs_state_by_type (type ) \
57+ (get_codecs_state(PyType_GetModuleByDef(type, &codecsmodule)))
58+
59+ #ifdef HAVE_ICONV
60+ typedef struct {
61+ PyObject_HEAD
62+ iconv_t cd ;
63+ char * encoding ;
64+ } iconv_decoder_object ;
65+
66+ #define iconv_decoder_CAST (op ) ((iconv_decoder_object *)(op))
67+ #endif
68+
4169/*[clinic input]
4270module _codecs
71+ class _codecs.IconvDecoder "iconv_decoder_object *" "get_codecs_state_by_type(type)->IconvDecoderType"
4372[clinic start generated code]*/
44- /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e1390e3da3cb9deb ]*/
73+ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=17a98f0bef095afe ]*/
4574
4675#include "pycore_runtime.h"
4776#include "clinic/_codecsmodule.c.h"
@@ -644,89 +673,126 @@ _codecs_code_page_decode_impl(PyObject *module, int codepage,
644673
645674#ifdef HAVE_ICONV
646675
647- #ifdef HAVE_ICONV
648- #define ICONV_STATE_CAPSULE "_codecs.iconv_state"
649-
650- static void
651- iconv_state_destructor (PyObject * capsule )
652- {
653- iconv_t * cdp = PyCapsule_GetPointer (capsule , ICONV_STATE_CAPSULE );
654- if (cdp == NULL ) {
655- PyErr_Clear ();
656- return ;
657- }
658- iconv_close (* cdp );
659- PyMem_Free (cdp );
660- }
661- #endif
662-
663676/*[clinic input]
664- _codecs.iconv_state
677+ @classmethod
678+ _codecs.IconvDecoder.__new__
665679
666680 encoding: str
667681 /
668682
669- Open an iconv conversion for decoding , to reuse across calls.
683+ Decoder holding one iconv conversion, to reuse across calls.
670684
671- The result is an opaque object. Reusing one conversion keeps the
672- shift state of a stateful encoding, such as ISO-2022-CN, across calls .
685+ Reusing one conversion keeps the shift state of a stateful encoding,
686+ such as ISO-2022-CN, from one call to the next .
673687[clinic start generated code]*/
674688
675689static PyObject *
676- _codecs_iconv_state_impl ( PyObject * module , const char * encoding )
677- /*[clinic end generated code: output=4100a9b65a64d65c input=6ffbfa5bb1d2d208 ]*/
690+ _codecs_IconvDecoder_impl ( PyTypeObject * type , const char * encoding )
691+ /*[clinic end generated code: output=6e5181abedc4ae7c input=c53769050ff2b196 ]*/
678692{
679- #ifdef HAVE_ICONV
680- iconv_t * cdp = PyMem_Malloc (sizeof (iconv_t ));
681- if (cdp == NULL ) {
693+ char * name = _PyMem_Strdup (encoding );
694+ if (name == NULL ) {
682695 return PyErr_NoMemory ();
683696 }
684- * cdp = _PyUnicode_IconvOpenDecoder (encoding );
685- if (* cdp == (iconv_t )- 1 ) {
686- PyMem_Free (cdp );
697+ iconv_t cd = _PyUnicode_IconvOpenDecoder (encoding );
698+ if (cd == (iconv_t )- 1 ) {
699+ PyMem_Free (name );
687700 return NULL ;
688701 }
689- PyObject * capsule = PyCapsule_New (cdp , ICONV_STATE_CAPSULE ,
690- iconv_state_destructor );
691- if (capsule == NULL ) {
692- iconv_close (* cdp );
693- PyMem_Free (cdp );
702+ iconv_decoder_object * self = (iconv_decoder_object * )type -> tp_alloc (type , 0 );
703+ if (self == NULL ) {
704+ iconv_close (cd );
705+ PyMem_Free (name );
694706 return NULL ;
695707 }
696- return capsule ;
697- #else
698- PyErr_SetString (PyExc_LookupError , "iconv is not available" );
699- return NULL ;
700- #endif
708+ self -> cd = cd ;
709+ self -> encoding = name ;
710+ return (PyObject * )self ;
701711}
702712
713+ /*[clinic input]
714+ _codecs.IconvDecoder.decode
715+
716+ data: Py_buffer
717+ errors: str(accept={str, NoneType}) = None
718+ final: bool = False
719+ /
720+ [clinic start generated code]*/
721+
722+ static PyObject *
723+ _codecs_IconvDecoder_decode_impl (iconv_decoder_object * self , Py_buffer * data ,
724+ const char * errors , int final )
725+ /*[clinic end generated code: output=0e8812b6b422fc97 input=9bea42dd438d03af]*/
726+ {
727+ Py_ssize_t consumed = data -> len ;
728+ PyObject * decoded = _PyUnicode_DecodeIconv (self -> encoding , data -> buf ,
729+ data -> len , errors ,
730+ final ? NULL : & consumed ,
731+ & self -> cd );
732+ return codec_tuple (decoded , consumed );
733+ }
734+
735+ static int
736+ iconv_decoder_traverse (PyObject * op , visitproc visit , void * arg )
737+ {
738+ Py_VISIT (Py_TYPE (op ));
739+ return 0 ;
740+ }
741+
742+ static void
743+ iconv_decoder_dealloc (PyObject * op )
744+ {
745+ iconv_decoder_object * self = iconv_decoder_CAST (op );
746+ PyTypeObject * tp = Py_TYPE (self );
747+ PyObject_GC_UnTrack (self );
748+ if (self -> cd != (iconv_t )- 1 ) {
749+ iconv_close (self -> cd );
750+ }
751+ PyMem_Free (self -> encoding );
752+ tp -> tp_free (self );
753+ Py_DECREF (tp );
754+ }
755+
756+ static PyMethodDef iconv_decoder_methods [] = {
757+ _CODECS_ICONVDECODER_DECODE_METHODDEF
758+ {NULL , NULL }
759+ };
760+
761+ static PyType_Slot iconv_decoder_slots [] = {
762+ {Py_tp_new , _codecs_IconvDecoder },
763+ {Py_tp_dealloc , iconv_decoder_dealloc },
764+ {Py_tp_traverse , iconv_decoder_traverse },
765+ {Py_tp_methods , iconv_decoder_methods },
766+ {Py_tp_doc , (void * )_codecs_IconvDecoder__doc__ },
767+ {0 , NULL }
768+ };
769+
770+ static PyType_Spec iconv_decoder_spec = {
771+ .name = "_codecs.IconvDecoder" ,
772+ .basicsize = sizeof (iconv_decoder_object ),
773+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE
774+ | Py_TPFLAGS_HAVE_GC ),
775+ .slots = iconv_decoder_slots ,
776+ };
777+
703778/*[clinic input]
704779_codecs.iconv_decode
705780 encoding: str
706781 data: Py_buffer
707782 errors: str(accept={str, NoneType}) = None
708783 final: bool = False
709- state: object = None
710784 /
711785[clinic start generated code]*/
712786
713787static PyObject *
714788_codecs_iconv_decode_impl (PyObject * module , const char * encoding ,
715- Py_buffer * data , const char * errors , int final ,
716- PyObject * state )
717- /*[clinic end generated code: output=ed99087a9b21d007 input=b23f4298c963f9c5]*/
789+ Py_buffer * data , const char * errors , int final )
790+ /*[clinic end generated code: output=6c6145a9decc2ba8 input=d15a04d7d3a3e0cd]*/
718791{
719- iconv_t * cdp = NULL ;
720- if (state != Py_None ) {
721- cdp = PyCapsule_GetPointer (state , ICONV_STATE_CAPSULE );
722- if (cdp == NULL ) {
723- return NULL ;
724- }
725- }
726792 Py_ssize_t consumed = data -> len ;
727793 PyObject * decoded = _PyUnicode_DecodeIconv (encoding , data -> buf , data -> len ,
728794 errors ,
729- final ? NULL : & consumed , cdp );
795+ final ? NULL : & consumed , NULL );
730796 return codec_tuple (decoded , consumed );
731797}
732798
@@ -1220,31 +1286,67 @@ static PyMethodDef _codecs_functions[] = {
12201286 _CODECS_CODE_PAGE_DECODE_METHODDEF
12211287 _CODECS_ICONV_ENCODE_METHODDEF
12221288 _CODECS_ICONV_DECODE_METHODDEF
1223- _CODECS_ICONV_STATE_METHODDEF
12241289 _CODECS_REGISTER_ERROR_METHODDEF
12251290 _CODECS__UNREGISTER_ERROR_METHODDEF
12261291 _CODECS_LOOKUP_ERROR_METHODDEF
12271292 _CODECS__NORMALIZE_ENCODING_METHODDEF
12281293 {NULL , NULL } /* sentinel */
12291294};
12301295
1296+ static int
1297+ _codecs_exec (PyObject * module )
1298+ {
1299+ #ifdef HAVE_ICONV
1300+ _codecs_state * state = get_codecs_state (module );
1301+ state -> IconvDecoderType = (PyTypeObject * )PyType_FromModuleAndSpec (
1302+ module , & iconv_decoder_spec , NULL );
1303+ if (state -> IconvDecoderType == NULL ) {
1304+ return -1 ;
1305+ }
1306+ if (PyModule_AddType (module , state -> IconvDecoderType ) < 0 ) {
1307+ return -1 ;
1308+ }
1309+ #endif
1310+ return 0 ;
1311+ }
1312+
1313+ static int
1314+ _codecs_traverse (PyObject * module , visitproc visit , void * arg )
1315+ {
1316+ Py_VISIT (get_codecs_state (module )-> IconvDecoderType );
1317+ return 0 ;
1318+ }
1319+
1320+ static int
1321+ _codecs_clear (PyObject * module )
1322+ {
1323+ Py_CLEAR (get_codecs_state (module )-> IconvDecoderType );
1324+ return 0 ;
1325+ }
1326+
1327+ static void
1328+ _codecs_free (void * module )
1329+ {
1330+ (void )_codecs_clear ((PyObject * )module );
1331+ }
1332+
12311333static PyModuleDef_Slot _codecs_slots [] = {
12321334 _Py_ABI_SLOT ,
1335+ {Py_mod_exec , _codecs_exec },
12331336 {Py_mod_multiple_interpreters , Py_MOD_PER_INTERPRETER_GIL_SUPPORTED },
12341337 {Py_mod_gil , Py_MOD_GIL_NOT_USED },
12351338 {0 , NULL }
12361339};
12371340
12381341static struct PyModuleDef codecsmodule = {
1239- PyModuleDef_HEAD_INIT ,
1240- "_codecs" ,
1241- NULL ,
1242- 0 ,
1243- _codecs_functions ,
1244- _codecs_slots ,
1245- NULL ,
1246- NULL ,
1247- NULL
1342+ .m_base = PyModuleDef_HEAD_INIT ,
1343+ .m_name = "_codecs" ,
1344+ .m_size = sizeof (_codecs_state ),
1345+ .m_methods = _codecs_functions ,
1346+ .m_slots = _codecs_slots ,
1347+ .m_traverse = _codecs_traverse ,
1348+ .m_clear = _codecs_clear ,
1349+ .m_free = _codecs_free ,
12481350};
12491351
12501352PyMODINIT_FUNC
0 commit comments