2 * multibytecodec.c: Common Multibyte Codec Implementation
4 * Written by Hye-Shik Chang <perky@FreeBSD.org>
7 #define PY_SSIZE_T_CLEAN
9 #include "structmember.h"
10 #include "multibytecodec.h"
13 const Py_UNICODE
*inbuf
, *inbuf_top
, *inbuf_end
;
14 unsigned char *outbuf
, *outbuf_end
;
15 PyObject
*excobj
, *outobj
;
16 } MultibyteEncodeBuffer
;
19 const unsigned char *inbuf
, *inbuf_top
, *inbuf_end
;
20 Py_UNICODE
*outbuf
, *outbuf_end
;
21 PyObject
*excobj
, *outobj
;
22 } MultibyteDecodeBuffer
;
24 PyDoc_STRVAR(MultibyteCodec_Encode__doc__
,
25 "I.encode(unicode[, errors]) -> (string, length consumed)\n\
27 Return an encoded string version of `unicode'. errors may be given to\n\
28 set a different error handling scheme. Default is 'strict' meaning that\n\
29 encoding errors raise a UnicodeEncodeError. Other possible values are\n\
30 'ignore', 'replace' and 'xmlcharrefreplace' as well as any other name\n\
31 registered with codecs.register_error that can handle UnicodeEncodeErrors.");
33 PyDoc_STRVAR(MultibyteCodec_Decode__doc__
,
34 "I.decode(string[, errors]) -> (unicodeobject, length consumed)\n\
36 Decodes `string' using I, an MultibyteCodec instance. errors may be given\n\
37 to set a different error handling scheme. Default is 'strict' meaning\n\
38 that encoding errors raise a UnicodeDecodeError. Other possible values\n\
39 are 'ignore' and 'replace' as well as any other name registerd with\n\
40 codecs.register_error that is able to handle UnicodeDecodeErrors.");
42 static char *codeckwarglist
[] = {"input", "errors", NULL
};
43 static char *incnewkwarglist
[] = {"errors", NULL
};
44 static char *incrementalkwarglist
[] = {"input", "final", NULL
};
45 static char *streamkwarglist
[] = {"stream", "errors", NULL
};
47 static PyObject
*multibytecodec_encode(MultibyteCodec
*,
48 MultibyteCodec_State
*, const Py_UNICODE
**, Py_ssize_t
,
51 #define MBENC_RESET MBENC_MAX<<1 /* reset after an encoding session */
54 make_tuple(PyObject
*object
, Py_ssize_t len
)
66 PyTuple_SET_ITEM(v
, 0, object
);
68 w
= PyInt_FromSsize_t(len
);
73 PyTuple_SET_ITEM(v
, 1, w
);
79 internal_error_callback(const char *errors
)
81 if (errors
== NULL
|| strcmp(errors
, "strict") == 0)
83 else if (strcmp(errors
, "ignore") == 0)
85 else if (strcmp(errors
, "replace") == 0)
88 return PyString_FromString(errors
);
92 call_error_callback(PyObject
*errors
, PyObject
*exc
)
94 PyObject
*args
, *cb
, *r
;
96 assert(PyString_Check(errors
));
97 cb
= PyCodec_LookupError(PyString_AS_STRING(errors
));
101 args
= PyTuple_New(1);
107 PyTuple_SET_ITEM(args
, 0, exc
);
110 r
= PyObject_CallObject(cb
, args
);
117 codecctx_errors_get(MultibyteStatefulCodecContext
*self
)
121 if (self
->errors
== ERROR_STRICT
)
123 else if (self
->errors
== ERROR_IGNORE
)
125 else if (self
->errors
== ERROR_REPLACE
)
128 Py_INCREF(self
->errors
);
132 return PyString_FromString(errors
);
136 codecctx_errors_set(MultibyteStatefulCodecContext
*self
, PyObject
*value
,
141 if (!PyString_Check(value
)) {
142 PyErr_SetString(PyExc_TypeError
, "errors must be a string");
146 cb
= internal_error_callback(PyString_AS_STRING(value
));
150 ERROR_DECREF(self
->errors
);
155 /* This getset handlers list is used by all the stateful codec objects */
156 static PyGetSetDef codecctx_getsets
[] = {
157 {"errors", (getter
)codecctx_errors_get
,
158 (setter
)codecctx_errors_set
,
159 PyDoc_STR("how to treat errors")},
164 expand_encodebuffer(MultibyteEncodeBuffer
*buf
, Py_ssize_t esize
)
166 Py_ssize_t orgpos
, orgsize
;
168 orgpos
= (Py_ssize_t
)((char *)buf
->outbuf
-
169 PyString_AS_STRING(buf
->outobj
));
170 orgsize
= PyString_GET_SIZE(buf
->outobj
);
171 if (_PyString_Resize(&buf
->outobj
, orgsize
+ (
172 esize
< (orgsize
>> 1) ? (orgsize
>> 1) | 1 : esize
)) == -1)
175 buf
->outbuf
= (unsigned char *)PyString_AS_STRING(buf
->outobj
) +orgpos
;
176 buf
->outbuf_end
= (unsigned char *)PyString_AS_STRING(buf
->outobj
)
177 + PyString_GET_SIZE(buf
->outobj
);
181 #define REQUIRE_ENCODEBUFFER(buf, s) { \
182 if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \
183 if (expand_encodebuffer(buf, s) == -1) \
188 expand_decodebuffer(MultibyteDecodeBuffer
*buf
, Py_ssize_t esize
)
190 Py_ssize_t orgpos
, orgsize
;
192 orgpos
= (Py_ssize_t
)(buf
->outbuf
- PyUnicode_AS_UNICODE(buf
->outobj
));
193 orgsize
= PyUnicode_GET_SIZE(buf
->outobj
);
194 if (PyUnicode_Resize(&buf
->outobj
, orgsize
+ (
195 esize
< (orgsize
>> 1) ? (orgsize
>> 1) | 1 : esize
)) == -1)
198 buf
->outbuf
= PyUnicode_AS_UNICODE(buf
->outobj
) + orgpos
;
199 buf
->outbuf_end
= PyUnicode_AS_UNICODE(buf
->outobj
)
200 + PyUnicode_GET_SIZE(buf
->outobj
);
204 #define REQUIRE_DECODEBUFFER(buf, s) { \
205 if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \
206 if (expand_decodebuffer(buf, s) == -1) \
212 * MultibyteCodec object
216 multibytecodec_encerror(MultibyteCodec
*codec
,
217 MultibyteCodec_State
*state
,
218 MultibyteEncodeBuffer
*buf
,
219 PyObject
*errors
, Py_ssize_t e
)
221 PyObject
*retobj
= NULL
, *retstr
= NULL
, *tobj
;
222 Py_ssize_t retstrsize
, newpos
;
223 Py_ssize_t esize
, start
, end
;
227 reason
= "illegal multibyte sequence";
233 REQUIRE_ENCODEBUFFER(buf
, -1);
234 return 0; /* retry it */
236 reason
= "incomplete multibyte sequence";
237 esize
= (Py_ssize_t
)(buf
->inbuf_end
- buf
->inbuf
);
240 PyErr_SetString(PyExc_RuntimeError
,
241 "internal codec error");
244 PyErr_SetString(PyExc_RuntimeError
,
245 "unknown runtime error");
250 if (errors
== ERROR_REPLACE
) {
251 const Py_UNICODE replchar
= '?', *inbuf
= &replchar
;
257 outleft
= (Py_ssize_t
)(buf
->outbuf_end
- buf
->outbuf
);
258 r
= codec
->encode(state
, codec
->config
, &inbuf
, 1,
259 &buf
->outbuf
, outleft
, 0);
260 if (r
== MBERR_TOOSMALL
) {
261 REQUIRE_ENCODEBUFFER(buf
, -1);
269 REQUIRE_ENCODEBUFFER(buf
, 1);
270 *buf
->outbuf
++ = '?';
273 if (errors
== ERROR_IGNORE
|| errors
== ERROR_REPLACE
) {
278 start
= (Py_ssize_t
)(buf
->inbuf
- buf
->inbuf_top
);
281 /* use cached exception object if available */
282 if (buf
->excobj
== NULL
) {
283 buf
->excobj
= PyUnicodeEncodeError_Create(codec
->encoding
,
285 buf
->inbuf_end
- buf
->inbuf_top
,
287 if (buf
->excobj
== NULL
)
291 if (PyUnicodeEncodeError_SetStart(buf
->excobj
, start
) != 0 ||
292 PyUnicodeEncodeError_SetEnd(buf
->excobj
, end
) != 0 ||
293 PyUnicodeEncodeError_SetReason(buf
->excobj
, reason
) != 0)
296 if (errors
== ERROR_STRICT
) {
297 PyCodec_StrictErrors(buf
->excobj
);
301 retobj
= call_error_callback(errors
, buf
->excobj
);
305 if (!PyTuple_Check(retobj
) || PyTuple_GET_SIZE(retobj
) != 2 ||
306 !PyUnicode_Check((tobj
= PyTuple_GET_ITEM(retobj
, 0))) ||
307 !(PyInt_Check(PyTuple_GET_ITEM(retobj
, 1)) ||
308 PyLong_Check(PyTuple_GET_ITEM(retobj
, 1)))) {
309 PyErr_SetString(PyExc_TypeError
,
310 "encoding error handler must return "
311 "(unicode, int) tuple");
316 const Py_UNICODE
*uraw
= PyUnicode_AS_UNICODE(tobj
);
318 retstr
= multibytecodec_encode(codec
, state
, &uraw
,
319 PyUnicode_GET_SIZE(tobj
), ERROR_STRICT
,
325 retstrsize
= PyString_GET_SIZE(retstr
);
326 REQUIRE_ENCODEBUFFER(buf
, retstrsize
);
328 memcpy(buf
->outbuf
, PyString_AS_STRING(retstr
), retstrsize
);
329 buf
->outbuf
+= retstrsize
;
331 newpos
= PyInt_AsSsize_t(PyTuple_GET_ITEM(retobj
, 1));
332 if (newpos
< 0 && !PyErr_Occurred())
333 newpos
+= (Py_ssize_t
)(buf
->inbuf_end
- buf
->inbuf_top
);
334 if (newpos
< 0 || buf
->inbuf_top
+ newpos
> buf
->inbuf_end
) {
336 PyErr_Format(PyExc_IndexError
,
337 "position %zd from error handler out of bounds",
341 buf
->inbuf
= buf
->inbuf_top
+ newpos
;
354 multibytecodec_decerror(MultibyteCodec
*codec
,
355 MultibyteCodec_State
*state
,
356 MultibyteDecodeBuffer
*buf
,
357 PyObject
*errors
, Py_ssize_t e
)
359 PyObject
*retobj
= NULL
, *retuni
= NULL
;
360 Py_ssize_t retunisize
, newpos
;
362 Py_ssize_t esize
, start
, end
;
365 reason
= "illegal multibyte sequence";
371 REQUIRE_DECODEBUFFER(buf
, -1);
372 return 0; /* retry it */
374 reason
= "incomplete multibyte sequence";
375 esize
= (Py_ssize_t
)(buf
->inbuf_end
- buf
->inbuf
);
378 PyErr_SetString(PyExc_RuntimeError
,
379 "internal codec error");
382 PyErr_SetString(PyExc_RuntimeError
,
383 "unknown runtime error");
388 if (errors
== ERROR_REPLACE
) {
389 REQUIRE_DECODEBUFFER(buf
, 1);
390 *buf
->outbuf
++ = Py_UNICODE_REPLACEMENT_CHARACTER
;
392 if (errors
== ERROR_IGNORE
|| errors
== ERROR_REPLACE
) {
397 start
= (Py_ssize_t
)(buf
->inbuf
- buf
->inbuf_top
);
400 /* use cached exception object if available */
401 if (buf
->excobj
== NULL
) {
402 buf
->excobj
= PyUnicodeDecodeError_Create(codec
->encoding
,
403 (const char *)buf
->inbuf_top
,
404 (Py_ssize_t
)(buf
->inbuf_end
- buf
->inbuf_top
),
406 if (buf
->excobj
== NULL
)
410 if (PyUnicodeDecodeError_SetStart(buf
->excobj
, start
) ||
411 PyUnicodeDecodeError_SetEnd(buf
->excobj
, end
) ||
412 PyUnicodeDecodeError_SetReason(buf
->excobj
, reason
))
415 if (errors
== ERROR_STRICT
) {
416 PyCodec_StrictErrors(buf
->excobj
);
420 retobj
= call_error_callback(errors
, buf
->excobj
);
424 if (!PyTuple_Check(retobj
) || PyTuple_GET_SIZE(retobj
) != 2 ||
425 !PyUnicode_Check((retuni
= PyTuple_GET_ITEM(retobj
, 0))) ||
426 !(PyInt_Check(PyTuple_GET_ITEM(retobj
, 1)) ||
427 PyLong_Check(PyTuple_GET_ITEM(retobj
, 1)))) {
428 PyErr_SetString(PyExc_TypeError
,
429 "decoding error handler must return "
430 "(unicode, int) tuple");
434 retunisize
= PyUnicode_GET_SIZE(retuni
);
435 if (retunisize
> 0) {
436 REQUIRE_DECODEBUFFER(buf
, retunisize
);
437 memcpy((char *)buf
->outbuf
, PyUnicode_AS_DATA(retuni
),
438 retunisize
* Py_UNICODE_SIZE
);
439 buf
->outbuf
+= retunisize
;
442 newpos
= PyInt_AsSsize_t(PyTuple_GET_ITEM(retobj
, 1));
443 if (newpos
< 0 && !PyErr_Occurred())
444 newpos
+= (Py_ssize_t
)(buf
->inbuf_end
- buf
->inbuf_top
);
445 if (newpos
< 0 || buf
->inbuf_top
+ newpos
> buf
->inbuf_end
) {
447 PyErr_Format(PyExc_IndexError
,
448 "position %zd from error handler out of bounds",
452 buf
->inbuf
= buf
->inbuf_top
+ newpos
;
462 multibytecodec_encode(MultibyteCodec
*codec
,
463 MultibyteCodec_State
*state
,
464 const Py_UNICODE
**data
, Py_ssize_t datalen
,
465 PyObject
*errors
, int flags
)
467 MultibyteEncodeBuffer buf
;
468 Py_ssize_t finalsize
, r
= 0;
471 return PyString_FromString("");
474 buf
.inbuf
= buf
.inbuf_top
= *data
;
475 buf
.inbuf_end
= buf
.inbuf_top
+ datalen
;
476 buf
.outobj
= PyString_FromStringAndSize(NULL
, datalen
* 2 + 16);
477 if (buf
.outobj
== NULL
)
479 buf
.outbuf
= (unsigned char *)PyString_AS_STRING(buf
.outobj
);
480 buf
.outbuf_end
= buf
.outbuf
+ PyString_GET_SIZE(buf
.outobj
);
482 while (buf
.inbuf
< buf
.inbuf_end
) {
483 Py_ssize_t inleft
, outleft
;
485 /* we don't reuse inleft and outleft here.
486 * error callbacks can relocate the cursor anywhere on buffer*/
487 inleft
= (Py_ssize_t
)(buf
.inbuf_end
- buf
.inbuf
);
488 outleft
= (Py_ssize_t
)(buf
.outbuf_end
- buf
.outbuf
);
489 r
= codec
->encode(state
, codec
->config
, &buf
.inbuf
, inleft
,
490 &buf
.outbuf
, outleft
, flags
);
492 if ((r
== 0) || (r
== MBERR_TOOFEW
&& !(flags
& MBENC_FLUSH
)))
494 else if (multibytecodec_encerror(codec
, state
, &buf
, errors
,r
))
496 else if (r
== MBERR_TOOFEW
)
500 if (codec
->encreset
!= NULL
)
504 outleft
= (Py_ssize_t
)(buf
.outbuf_end
- buf
.outbuf
);
505 r
= codec
->encreset(state
, codec
->config
, &buf
.outbuf
,
509 else if (multibytecodec_encerror(codec
, state
,
514 finalsize
= (Py_ssize_t
)((char *)buf
.outbuf
-
515 PyString_AS_STRING(buf
.outobj
));
517 if (finalsize
!= PyString_GET_SIZE(buf
.outobj
))
518 if (_PyString_Resize(&buf
.outobj
, finalsize
) == -1)
521 Py_XDECREF(buf
.excobj
);
525 Py_XDECREF(buf
.excobj
);
526 Py_XDECREF(buf
.outobj
);
531 MultibyteCodec_Encode(MultibyteCodecObject
*self
,
532 PyObject
*args
, PyObject
*kwargs
)
534 MultibyteCodec_State state
;
536 PyObject
*errorcb
, *r
, *arg
, *ucvt
;
537 const char *errors
= NULL
;
540 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O|z:encode",
541 codeckwarglist
, &arg
, &errors
))
544 if (PyUnicode_Check(arg
))
547 arg
= ucvt
= PyObject_Unicode(arg
);
550 else if (!PyUnicode_Check(arg
)) {
551 PyErr_SetString(PyExc_TypeError
,
552 "couldn't convert the object to unicode.");
558 data
= PyUnicode_AS_UNICODE(arg
);
559 datalen
= PyUnicode_GET_SIZE(arg
);
561 errorcb
= internal_error_callback(errors
);
562 if (errorcb
== NULL
) {
567 if (self
->codec
->encinit
!= NULL
&&
568 self
->codec
->encinit(&state
, self
->codec
->config
) != 0)
570 r
= multibytecodec_encode(self
->codec
, &state
,
571 (const Py_UNICODE
**)&data
, datalen
, errorcb
,
572 MBENC_FLUSH
| MBENC_RESET
);
576 ERROR_DECREF(errorcb
);
578 return make_tuple(r
, datalen
);
581 ERROR_DECREF(errorcb
);
587 MultibyteCodec_Decode(MultibyteCodecObject
*self
,
588 PyObject
*args
, PyObject
*kwargs
)
590 MultibyteCodec_State state
;
591 MultibyteDecodeBuffer buf
;
593 const char *data
, *errors
= NULL
;
594 Py_ssize_t datalen
, finalsize
;
596 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s#|z:decode",
597 codeckwarglist
, &data
, &datalen
, &errors
))
600 errorcb
= internal_error_callback(errors
);
605 ERROR_DECREF(errorcb
);
606 return make_tuple(PyUnicode_FromUnicode(NULL
, 0), 0);
610 buf
.inbuf
= buf
.inbuf_top
= (unsigned char *)data
;
611 buf
.inbuf_end
= buf
.inbuf_top
+ datalen
;
612 buf
.outobj
= PyUnicode_FromUnicode(NULL
, datalen
);
613 if (buf
.outobj
== NULL
)
615 buf
.outbuf
= PyUnicode_AS_UNICODE(buf
.outobj
);
616 buf
.outbuf_end
= buf
.outbuf
+ PyUnicode_GET_SIZE(buf
.outobj
);
618 if (self
->codec
->decinit
!= NULL
&&
619 self
->codec
->decinit(&state
, self
->codec
->config
) != 0)
622 while (buf
.inbuf
< buf
.inbuf_end
) {
623 Py_ssize_t inleft
, outleft
, r
;
625 inleft
= (Py_ssize_t
)(buf
.inbuf_end
- buf
.inbuf
);
626 outleft
= (Py_ssize_t
)(buf
.outbuf_end
- buf
.outbuf
);
628 r
= self
->codec
->decode(&state
, self
->codec
->config
,
629 &buf
.inbuf
, inleft
, &buf
.outbuf
, outleft
);
632 else if (multibytecodec_decerror(self
->codec
, &state
,
637 finalsize
= (Py_ssize_t
)(buf
.outbuf
-
638 PyUnicode_AS_UNICODE(buf
.outobj
));
640 if (finalsize
!= PyUnicode_GET_SIZE(buf
.outobj
))
641 if (PyUnicode_Resize(&buf
.outobj
, finalsize
) == -1)
644 Py_XDECREF(buf
.excobj
);
645 ERROR_DECREF(errorcb
);
646 return make_tuple(buf
.outobj
, datalen
);
649 ERROR_DECREF(errorcb
);
650 Py_XDECREF(buf
.excobj
);
651 Py_XDECREF(buf
.outobj
);
656 static struct PyMethodDef multibytecodec_methods
[] = {
657 {"encode", (PyCFunction
)MultibyteCodec_Encode
,
658 METH_VARARGS
| METH_KEYWORDS
,
659 MultibyteCodec_Encode__doc__
},
660 {"decode", (PyCFunction
)MultibyteCodec_Decode
,
661 METH_VARARGS
| METH_KEYWORDS
,
662 MultibyteCodec_Decode__doc__
},
667 multibytecodec_dealloc(MultibyteCodecObject
*self
)
672 static PyTypeObject MultibyteCodec_Type
= {
673 PyVarObject_HEAD_INIT(NULL
, 0)
674 "MultibyteCodec", /* tp_name */
675 sizeof(MultibyteCodecObject
), /* tp_basicsize */
678 (destructor
)multibytecodec_dealloc
, /* tp_dealloc */
684 0, /* tp_as_number */
685 0, /* tp_as_sequence */
686 0, /* tp_as_mapping */
690 PyObject_GenericGetAttr
, /* tp_getattro */
692 0, /* tp_as_buffer */
693 Py_TPFLAGS_DEFAULT
, /* tp_flags */
697 0, /* tp_richcompare */
698 0, /* tp_weaklistoffset */
701 multibytecodec_methods
, /* tp_methods */
706 * Utility functions for stateful codec mechanism
709 #define STATEFUL_DCTX(o) ((MultibyteStatefulDecoderContext *)(o))
710 #define STATEFUL_ECTX(o) ((MultibyteStatefulEncoderContext *)(o))
713 encoder_encode_stateful(MultibyteStatefulEncoderContext
*ctx
,
714 PyObject
*unistr
, int final
)
716 PyObject
*ucvt
, *r
= NULL
;
717 Py_UNICODE
*inbuf
, *inbuf_end
, *inbuf_tmp
= NULL
;
718 Py_ssize_t datalen
, origpending
;
720 if (PyUnicode_Check(unistr
))
723 unistr
= ucvt
= PyObject_Unicode(unistr
);
726 else if (!PyUnicode_Check(unistr
)) {
727 PyErr_SetString(PyExc_TypeError
,
728 "couldn't convert the object to unicode.");
734 datalen
= PyUnicode_GET_SIZE(unistr
);
735 origpending
= ctx
->pendingsize
;
737 if (origpending
> 0) {
738 inbuf_tmp
= PyMem_New(Py_UNICODE
, datalen
+ ctx
->pendingsize
);
739 if (inbuf_tmp
== NULL
)
741 memcpy(inbuf_tmp
, ctx
->pending
,
742 Py_UNICODE_SIZE
* ctx
->pendingsize
);
743 memcpy(inbuf_tmp
+ ctx
->pendingsize
,
744 PyUnicode_AS_UNICODE(unistr
),
745 Py_UNICODE_SIZE
* datalen
);
746 datalen
+= ctx
->pendingsize
;
747 ctx
->pendingsize
= 0;
751 inbuf
= (Py_UNICODE
*)PyUnicode_AS_UNICODE(unistr
);
753 inbuf_end
= inbuf
+ datalen
;
755 r
= multibytecodec_encode(ctx
->codec
, &ctx
->state
,
756 (const Py_UNICODE
**)&inbuf
,
757 datalen
, ctx
->errors
, final
? MBENC_FLUSH
: 0);
759 /* recover the original pending buffer */
761 memcpy(ctx
->pending
, inbuf_tmp
,
762 Py_UNICODE_SIZE
* origpending
);
763 ctx
->pendingsize
= origpending
;
767 if (inbuf
< inbuf_end
) {
768 ctx
->pendingsize
= (Py_ssize_t
)(inbuf_end
- inbuf
);
769 if (ctx
->pendingsize
> MAXENCPENDING
) {
770 /* normal codecs can't reach here */
771 ctx
->pendingsize
= 0;
772 PyErr_SetString(PyExc_UnicodeError
,
773 "pending buffer overflow");
776 memcpy(ctx
->pending
, inbuf
,
777 ctx
->pendingsize
* Py_UNICODE_SIZE
);
780 if (inbuf_tmp
!= NULL
)
781 PyMem_Del(inbuf_tmp
);
786 if (inbuf_tmp
!= NULL
)
787 PyMem_Del(inbuf_tmp
);
794 decoder_append_pending(MultibyteStatefulDecoderContext
*ctx
,
795 MultibyteDecodeBuffer
*buf
)
797 Py_ssize_t npendings
;
799 npendings
= (Py_ssize_t
)(buf
->inbuf_end
- buf
->inbuf
);
800 if (npendings
+ ctx
->pendingsize
> MAXDECPENDING
) {
801 PyErr_SetString(PyExc_UnicodeError
, "pending buffer overflow");
804 memcpy(ctx
->pending
+ ctx
->pendingsize
, buf
->inbuf
, npendings
);
805 ctx
->pendingsize
+= npendings
;
810 decoder_prepare_buffer(MultibyteDecodeBuffer
*buf
, const char *data
,
813 buf
->inbuf
= buf
->inbuf_top
= (const unsigned char *)data
;
814 buf
->inbuf_end
= buf
->inbuf_top
+ size
;
815 if (buf
->outobj
== NULL
) { /* only if outobj is not allocated yet */
816 buf
->outobj
= PyUnicode_FromUnicode(NULL
, size
);
817 if (buf
->outobj
== NULL
)
819 buf
->outbuf
= PyUnicode_AS_UNICODE(buf
->outobj
);
820 buf
->outbuf_end
= buf
->outbuf
+
821 PyUnicode_GET_SIZE(buf
->outobj
);
828 decoder_feed_buffer(MultibyteStatefulDecoderContext
*ctx
,
829 MultibyteDecodeBuffer
*buf
)
831 while (buf
->inbuf
< buf
->inbuf_end
) {
832 Py_ssize_t inleft
, outleft
;
835 inleft
= (Py_ssize_t
)(buf
->inbuf_end
- buf
->inbuf
);
836 outleft
= (Py_ssize_t
)(buf
->outbuf_end
- buf
->outbuf
);
838 r
= ctx
->codec
->decode(&ctx
->state
, ctx
->codec
->config
,
839 &buf
->inbuf
, inleft
, &buf
->outbuf
, outleft
);
840 if (r
== 0 || r
== MBERR_TOOFEW
)
842 else if (multibytecodec_decerror(ctx
->codec
, &ctx
->state
,
843 buf
, ctx
->errors
, r
))
851 * MultibyteIncrementalEncoder object
855 mbiencoder_encode(MultibyteIncrementalEncoderObject
*self
,
856 PyObject
*args
, PyObject
*kwargs
)
861 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O|i:encode",
862 incrementalkwarglist
, &data
, &final
))
865 return encoder_encode_stateful(STATEFUL_ECTX(self
), data
, final
);
869 mbiencoder_reset(MultibyteIncrementalEncoderObject
*self
)
871 if (self
->codec
->decreset
!= NULL
&&
872 self
->codec
->decreset(&self
->state
, self
->codec
->config
) != 0)
874 self
->pendingsize
= 0;
879 static struct PyMethodDef mbiencoder_methods
[] = {
880 {"encode", (PyCFunction
)mbiencoder_encode
,
881 METH_VARARGS
| METH_KEYWORDS
, NULL
},
882 {"reset", (PyCFunction
)mbiencoder_reset
,
888 mbiencoder_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
890 MultibyteIncrementalEncoderObject
*self
;
891 PyObject
*codec
= NULL
;
894 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|s:IncrementalEncoder",
895 incnewkwarglist
, &errors
))
898 self
= (MultibyteIncrementalEncoderObject
*)type
->tp_alloc(type
, 0);
902 codec
= PyObject_GetAttrString((PyObject
*)type
, "codec");
905 if (!MultibyteCodec_Check(codec
)) {
906 PyErr_SetString(PyExc_TypeError
, "codec is unexpected type");
910 self
->codec
= ((MultibyteCodecObject
*)codec
)->codec
;
911 self
->pendingsize
= 0;
912 self
->errors
= internal_error_callback(errors
);
913 if (self
->errors
== NULL
)
915 if (self
->codec
->encinit
!= NULL
&&
916 self
->codec
->encinit(&self
->state
, self
->codec
->config
) != 0)
920 return (PyObject
*)self
;
929 mbiencoder_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
935 mbiencoder_traverse(MultibyteIncrementalEncoderObject
*self
,
936 visitproc visit
, void *arg
)
938 if (ERROR_ISCUSTOM(self
->errors
))
939 Py_VISIT(self
->errors
);
944 mbiencoder_dealloc(MultibyteIncrementalEncoderObject
*self
)
946 PyObject_GC_UnTrack(self
);
947 ERROR_DECREF(self
->errors
);
948 Py_TYPE(self
)->tp_free(self
);
951 static PyTypeObject MultibyteIncrementalEncoder_Type
= {
952 PyVarObject_HEAD_INIT(NULL
, 0)
953 "MultibyteIncrementalEncoder", /* tp_name */
954 sizeof(MultibyteIncrementalEncoderObject
), /* tp_basicsize */
957 (destructor
)mbiencoder_dealloc
, /* tp_dealloc */
963 0, /* tp_as_number */
964 0, /* tp_as_sequence */
965 0, /* tp_as_mapping */
969 PyObject_GenericGetAttr
, /* tp_getattro */
971 0, /* tp_as_buffer */
972 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
973 | Py_TPFLAGS_BASETYPE
, /* tp_flags */
975 (traverseproc
)mbiencoder_traverse
, /* tp_traverse */
977 0, /* tp_richcompare */
978 0, /* tp_weaklistoffset */
981 mbiencoder_methods
, /* tp_methods */
983 codecctx_getsets
, /* tp_getset */
986 0, /* tp_descr_get */
987 0, /* tp_descr_set */
988 0, /* tp_dictoffset */
989 mbiencoder_init
, /* tp_init */
991 mbiencoder_new
, /* tp_new */
996 * MultibyteIncrementalDecoder object
1000 mbidecoder_decode(MultibyteIncrementalDecoderObject
*self
,
1001 PyObject
*args
, PyObject
*kwargs
)
1003 MultibyteDecodeBuffer buf
;
1005 Py_ssize_t wsize
, finalsize
= 0, size
, origpending
;
1008 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "t#|i:decode",
1009 incrementalkwarglist
, &data
, &size
, &final
))
1012 buf
.outobj
= buf
.excobj
= NULL
;
1013 origpending
= self
->pendingsize
;
1015 if (self
->pendingsize
== 0) {
1020 wsize
= size
+ self
->pendingsize
;
1021 wdata
= PyMem_Malloc(wsize
);
1024 memcpy(wdata
, self
->pending
, self
->pendingsize
);
1025 memcpy(wdata
+ self
->pendingsize
, data
, size
);
1026 self
->pendingsize
= 0;
1029 if (decoder_prepare_buffer(&buf
, wdata
, wsize
) != 0)
1032 if (decoder_feed_buffer(STATEFUL_DCTX(self
), &buf
))
1035 if (final
&& buf
.inbuf
< buf
.inbuf_end
) {
1036 if (multibytecodec_decerror(self
->codec
, &self
->state
,
1037 &buf
, self
->errors
, MBERR_TOOFEW
)) {
1038 /* recover the original pending buffer */
1039 memcpy(self
->pending
, wdata
, origpending
);
1040 self
->pendingsize
= origpending
;
1045 if (buf
.inbuf
< buf
.inbuf_end
) { /* pending sequence still exists */
1046 if (decoder_append_pending(STATEFUL_DCTX(self
), &buf
) != 0)
1050 finalsize
= (Py_ssize_t
)(buf
.outbuf
- PyUnicode_AS_UNICODE(buf
.outobj
));
1051 if (finalsize
!= PyUnicode_GET_SIZE(buf
.outobj
))
1052 if (PyUnicode_Resize(&buf
.outobj
, finalsize
) == -1)
1057 Py_XDECREF(buf
.excobj
);
1061 if (wdata
!= NULL
&& wdata
!= data
)
1063 Py_XDECREF(buf
.excobj
);
1064 Py_XDECREF(buf
.outobj
);
1069 mbidecoder_reset(MultibyteIncrementalDecoderObject
*self
)
1071 if (self
->codec
->decreset
!= NULL
&&
1072 self
->codec
->decreset(&self
->state
, self
->codec
->config
) != 0)
1074 self
->pendingsize
= 0;
1079 static struct PyMethodDef mbidecoder_methods
[] = {
1080 {"decode", (PyCFunction
)mbidecoder_decode
,
1081 METH_VARARGS
| METH_KEYWORDS
, NULL
},
1082 {"reset", (PyCFunction
)mbidecoder_reset
,
1088 mbidecoder_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
1090 MultibyteIncrementalDecoderObject
*self
;
1091 PyObject
*codec
= NULL
;
1092 char *errors
= NULL
;
1094 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|s:IncrementalDecoder",
1095 incnewkwarglist
, &errors
))
1098 self
= (MultibyteIncrementalDecoderObject
*)type
->tp_alloc(type
, 0);
1102 codec
= PyObject_GetAttrString((PyObject
*)type
, "codec");
1105 if (!MultibyteCodec_Check(codec
)) {
1106 PyErr_SetString(PyExc_TypeError
, "codec is unexpected type");
1110 self
->codec
= ((MultibyteCodecObject
*)codec
)->codec
;
1111 self
->pendingsize
= 0;
1112 self
->errors
= internal_error_callback(errors
);
1113 if (self
->errors
== NULL
)
1115 if (self
->codec
->decinit
!= NULL
&&
1116 self
->codec
->decinit(&self
->state
, self
->codec
->config
) != 0)
1120 return (PyObject
*)self
;
1129 mbidecoder_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
1135 mbidecoder_traverse(MultibyteIncrementalDecoderObject
*self
,
1136 visitproc visit
, void *arg
)
1138 if (ERROR_ISCUSTOM(self
->errors
))
1139 Py_VISIT(self
->errors
);
1144 mbidecoder_dealloc(MultibyteIncrementalDecoderObject
*self
)
1146 PyObject_GC_UnTrack(self
);
1147 ERROR_DECREF(self
->errors
);
1148 Py_TYPE(self
)->tp_free(self
);
1151 static PyTypeObject MultibyteIncrementalDecoder_Type
= {
1152 PyVarObject_HEAD_INIT(NULL
, 0)
1153 "MultibyteIncrementalDecoder", /* tp_name */
1154 sizeof(MultibyteIncrementalDecoderObject
), /* tp_basicsize */
1155 0, /* tp_itemsize */
1157 (destructor
)mbidecoder_dealloc
, /* tp_dealloc */
1163 0, /* tp_as_number */
1164 0, /* tp_as_sequence */
1165 0, /* tp_as_mapping */
1169 PyObject_GenericGetAttr
, /* tp_getattro */
1170 0, /* tp_setattro */
1171 0, /* tp_as_buffer */
1172 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
1173 | Py_TPFLAGS_BASETYPE
, /* tp_flags */
1175 (traverseproc
)mbidecoder_traverse
, /* tp_traverse */
1177 0, /* tp_richcompare */
1178 0, /* tp_weaklistoffset */
1181 mbidecoder_methods
, /* tp_methods */
1183 codecctx_getsets
, /* tp_getset */
1186 0, /* tp_descr_get */
1187 0, /* tp_descr_set */
1188 0, /* tp_dictoffset */
1189 mbidecoder_init
, /* tp_init */
1191 mbidecoder_new
, /* tp_new */
1196 * MultibyteStreamReader object
1200 mbstreamreader_iread(MultibyteStreamReaderObject
*self
,
1201 const char *method
, Py_ssize_t sizehint
)
1203 MultibyteDecodeBuffer buf
;
1205 Py_ssize_t rsize
, finalsize
= 0;
1208 return PyUnicode_FromUnicode(NULL
, 0);
1210 buf
.outobj
= buf
.excobj
= NULL
;
1217 cres
= PyObject_CallMethod(self
->stream
,
1218 (char *)method
, NULL
);
1220 cres
= PyObject_CallMethod(self
->stream
,
1221 (char *)method
, "i", sizehint
);
1225 if (!PyString_Check(cres
)) {
1226 PyErr_SetString(PyExc_TypeError
,
1227 "stream function returned a "
1228 "non-string object");
1232 endoffile
= (PyString_GET_SIZE(cres
) == 0);
1234 if (self
->pendingsize
> 0) {
1238 rsize
= PyString_GET_SIZE(cres
) + self
->pendingsize
;
1239 ctr
= PyString_FromStringAndSize(NULL
, rsize
);
1242 ctrdata
= PyString_AS_STRING(ctr
);
1243 memcpy(ctrdata
, self
->pending
, self
->pendingsize
);
1244 memcpy(ctrdata
+ self
->pendingsize
,
1245 PyString_AS_STRING(cres
),
1246 PyString_GET_SIZE(cres
));
1249 self
->pendingsize
= 0;
1252 rsize
= PyString_GET_SIZE(cres
);
1253 if (decoder_prepare_buffer(&buf
, PyString_AS_STRING(cres
),
1257 if (rsize
> 0 && decoder_feed_buffer(
1258 (MultibyteStatefulDecoderContext
*)self
, &buf
))
1261 if (endoffile
|| sizehint
< 0) {
1262 if (buf
.inbuf
< buf
.inbuf_end
&&
1263 multibytecodec_decerror(self
->codec
, &self
->state
,
1264 &buf
, self
->errors
, MBERR_TOOFEW
))
1268 if (buf
.inbuf
< buf
.inbuf_end
) { /* pending sequence exists */
1269 if (decoder_append_pending(STATEFUL_DCTX(self
),
1274 finalsize
= (Py_ssize_t
)(buf
.outbuf
-
1275 PyUnicode_AS_UNICODE(buf
.outobj
));
1279 if (sizehint
< 0 || finalsize
!= 0 || rsize
== 0)
1282 sizehint
= 1; /* read 1 more byte and retry */
1285 if (finalsize
!= PyUnicode_GET_SIZE(buf
.outobj
))
1286 if (PyUnicode_Resize(&buf
.outobj
, finalsize
) == -1)
1290 Py_XDECREF(buf
.excobj
);
1295 Py_XDECREF(buf
.excobj
);
1296 Py_XDECREF(buf
.outobj
);
1301 mbstreamreader_read(MultibyteStreamReaderObject
*self
, PyObject
*args
)
1303 PyObject
*sizeobj
= NULL
;
1306 if (!PyArg_UnpackTuple(args
, "read", 0, 1, &sizeobj
))
1309 if (sizeobj
== Py_None
|| sizeobj
== NULL
)
1311 else if (PyInt_Check(sizeobj
))
1312 size
= PyInt_AsSsize_t(sizeobj
);
1314 PyErr_SetString(PyExc_TypeError
, "arg 1 must be an integer");
1318 return mbstreamreader_iread(self
, "read", size
);
1322 mbstreamreader_readline(MultibyteStreamReaderObject
*self
, PyObject
*args
)
1324 PyObject
*sizeobj
= NULL
;
1327 if (!PyArg_UnpackTuple(args
, "readline", 0, 1, &sizeobj
))
1330 if (sizeobj
== Py_None
|| sizeobj
== NULL
)
1332 else if (PyInt_Check(sizeobj
))
1333 size
= PyInt_AsSsize_t(sizeobj
);
1335 PyErr_SetString(PyExc_TypeError
, "arg 1 must be an integer");
1339 return mbstreamreader_iread(self
, "readline", size
);
1343 mbstreamreader_readlines(MultibyteStreamReaderObject
*self
, PyObject
*args
)
1345 PyObject
*sizehintobj
= NULL
, *r
, *sr
;
1346 Py_ssize_t sizehint
;
1348 if (!PyArg_UnpackTuple(args
, "readlines", 0, 1, &sizehintobj
))
1351 if (sizehintobj
== Py_None
|| sizehintobj
== NULL
)
1353 else if (PyInt_Check(sizehintobj
))
1354 sizehint
= PyInt_AsSsize_t(sizehintobj
);
1356 PyErr_SetString(PyExc_TypeError
, "arg 1 must be an integer");
1360 r
= mbstreamreader_iread(self
, "read", sizehint
);
1364 sr
= PyUnicode_Splitlines(r
, 1);
1370 mbstreamreader_reset(MultibyteStreamReaderObject
*self
)
1372 if (self
->codec
->decreset
!= NULL
&&
1373 self
->codec
->decreset(&self
->state
, self
->codec
->config
) != 0)
1375 self
->pendingsize
= 0;
1380 static struct PyMethodDef mbstreamreader_methods
[] = {
1381 {"read", (PyCFunction
)mbstreamreader_read
,
1382 METH_VARARGS
, NULL
},
1383 {"readline", (PyCFunction
)mbstreamreader_readline
,
1384 METH_VARARGS
, NULL
},
1385 {"readlines", (PyCFunction
)mbstreamreader_readlines
,
1386 METH_VARARGS
, NULL
},
1387 {"reset", (PyCFunction
)mbstreamreader_reset
,
1392 static PyMemberDef mbstreamreader_members
[] = {
1393 {"stream", T_OBJECT
,
1394 offsetof(MultibyteStreamReaderObject
, stream
),
1400 mbstreamreader_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
1402 MultibyteStreamReaderObject
*self
;
1403 PyObject
*stream
, *codec
= NULL
;
1404 char *errors
= NULL
;
1406 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|s:StreamReader",
1407 streamkwarglist
, &stream
, &errors
))
1410 self
= (MultibyteStreamReaderObject
*)type
->tp_alloc(type
, 0);
1414 codec
= PyObject_GetAttrString((PyObject
*)type
, "codec");
1417 if (!MultibyteCodec_Check(codec
)) {
1418 PyErr_SetString(PyExc_TypeError
, "codec is unexpected type");
1422 self
->codec
= ((MultibyteCodecObject
*)codec
)->codec
;
1423 self
->stream
= stream
;
1425 self
->pendingsize
= 0;
1426 self
->errors
= internal_error_callback(errors
);
1427 if (self
->errors
== NULL
)
1429 if (self
->codec
->decinit
!= NULL
&&
1430 self
->codec
->decinit(&self
->state
, self
->codec
->config
) != 0)
1434 return (PyObject
*)self
;
1443 mbstreamreader_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
1449 mbstreamreader_traverse(MultibyteStreamReaderObject
*self
,
1450 visitproc visit
, void *arg
)
1452 if (ERROR_ISCUSTOM(self
->errors
))
1453 Py_VISIT(self
->errors
);
1454 Py_VISIT(self
->stream
);
1459 mbstreamreader_dealloc(MultibyteStreamReaderObject
*self
)
1461 PyObject_GC_UnTrack(self
);
1462 ERROR_DECREF(self
->errors
);
1463 Py_DECREF(self
->stream
);
1464 Py_TYPE(self
)->tp_free(self
);
1467 static PyTypeObject MultibyteStreamReader_Type
= {
1468 PyVarObject_HEAD_INIT(NULL
, 0)
1469 "MultibyteStreamReader", /* tp_name */
1470 sizeof(MultibyteStreamReaderObject
), /* tp_basicsize */
1471 0, /* tp_itemsize */
1473 (destructor
)mbstreamreader_dealloc
, /* tp_dealloc */
1479 0, /* tp_as_number */
1480 0, /* tp_as_sequence */
1481 0, /* tp_as_mapping */
1485 PyObject_GenericGetAttr
, /* tp_getattro */
1486 0, /* tp_setattro */
1487 0, /* tp_as_buffer */
1488 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
1489 | Py_TPFLAGS_BASETYPE
, /* tp_flags */
1491 (traverseproc
)mbstreamreader_traverse
, /* tp_traverse */
1493 0, /* tp_richcompare */
1494 0, /* tp_weaklistoffset */
1497 mbstreamreader_methods
, /* tp_methods */
1498 mbstreamreader_members
, /* tp_members */
1499 codecctx_getsets
, /* tp_getset */
1502 0, /* tp_descr_get */
1503 0, /* tp_descr_set */
1504 0, /* tp_dictoffset */
1505 mbstreamreader_init
, /* tp_init */
1507 mbstreamreader_new
, /* tp_new */
1512 * MultibyteStreamWriter object
1516 mbstreamwriter_iwrite(MultibyteStreamWriterObject
*self
,
1521 str
= encoder_encode_stateful(STATEFUL_ECTX(self
), unistr
, 0);
1525 wr
= PyObject_CallMethod(self
->stream
, "write", "O", str
);
1535 mbstreamwriter_write(MultibyteStreamWriterObject
*self
, PyObject
*strobj
)
1537 if (mbstreamwriter_iwrite(self
, strobj
))
1544 mbstreamwriter_writelines(MultibyteStreamWriterObject
*self
, PyObject
*lines
)
1549 if (!PySequence_Check(lines
)) {
1550 PyErr_SetString(PyExc_TypeError
,
1551 "arg must be a sequence object");
1555 for (i
= 0; i
< PySequence_Length(lines
); i
++) {
1556 /* length can be changed even within this loop */
1557 strobj
= PySequence_GetItem(lines
, i
);
1561 r
= mbstreamwriter_iwrite(self
, strobj
);
1571 mbstreamwriter_reset(MultibyteStreamWriterObject
*self
)
1573 const Py_UNICODE
*pending
;
1576 pending
= self
->pending
;
1577 pwrt
= multibytecodec_encode(self
->codec
, &self
->state
,
1578 &pending
, self
->pendingsize
, self
->errors
,
1579 MBENC_FLUSH
| MBENC_RESET
);
1580 /* some pending buffer can be truncated when UnicodeEncodeError is
1581 * raised on 'strict' mode. but, 'reset' method is designed to
1582 * reset the pending buffer or states so failed string sequence
1583 * ought to be missed */
1584 self
->pendingsize
= 0;
1588 if (PyString_Size(pwrt
) > 0) {
1590 wr
= PyObject_CallMethod(self
->stream
, "write", "O", pwrt
);
1602 mbstreamwriter_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
1604 MultibyteStreamWriterObject
*self
;
1605 PyObject
*stream
, *codec
= NULL
;
1606 char *errors
= NULL
;
1608 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|s:StreamWriter",
1609 streamkwarglist
, &stream
, &errors
))
1612 self
= (MultibyteStreamWriterObject
*)type
->tp_alloc(type
, 0);
1616 codec
= PyObject_GetAttrString((PyObject
*)type
, "codec");
1619 if (!MultibyteCodec_Check(codec
)) {
1620 PyErr_SetString(PyExc_TypeError
, "codec is unexpected type");
1624 self
->codec
= ((MultibyteCodecObject
*)codec
)->codec
;
1625 self
->stream
= stream
;
1627 self
->pendingsize
= 0;
1628 self
->errors
= internal_error_callback(errors
);
1629 if (self
->errors
== NULL
)
1631 if (self
->codec
->encinit
!= NULL
&&
1632 self
->codec
->encinit(&self
->state
, self
->codec
->config
) != 0)
1636 return (PyObject
*)self
;
1645 mbstreamwriter_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
1651 mbstreamwriter_traverse(MultibyteStreamWriterObject
*self
,
1652 visitproc visit
, void *arg
)
1654 if (ERROR_ISCUSTOM(self
->errors
))
1655 Py_VISIT(self
->errors
);
1656 Py_VISIT(self
->stream
);
1661 mbstreamwriter_dealloc(MultibyteStreamWriterObject
*self
)
1663 PyObject_GC_UnTrack(self
);
1664 ERROR_DECREF(self
->errors
);
1665 Py_DECREF(self
->stream
);
1666 Py_TYPE(self
)->tp_free(self
);
1669 static struct PyMethodDef mbstreamwriter_methods
[] = {
1670 {"write", (PyCFunction
)mbstreamwriter_write
,
1672 {"writelines", (PyCFunction
)mbstreamwriter_writelines
,
1674 {"reset", (PyCFunction
)mbstreamwriter_reset
,
1679 static PyMemberDef mbstreamwriter_members
[] = {
1680 {"stream", T_OBJECT
,
1681 offsetof(MultibyteStreamWriterObject
, stream
),
1686 static PyTypeObject MultibyteStreamWriter_Type
= {
1687 PyVarObject_HEAD_INIT(NULL
, 0)
1688 "MultibyteStreamWriter", /* tp_name */
1689 sizeof(MultibyteStreamWriterObject
), /* tp_basicsize */
1690 0, /* tp_itemsize */
1692 (destructor
)mbstreamwriter_dealloc
, /* tp_dealloc */
1698 0, /* tp_as_number */
1699 0, /* tp_as_sequence */
1700 0, /* tp_as_mapping */
1704 PyObject_GenericGetAttr
, /* tp_getattro */
1705 0, /* tp_setattro */
1706 0, /* tp_as_buffer */
1707 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
1708 | Py_TPFLAGS_BASETYPE
, /* tp_flags */
1710 (traverseproc
)mbstreamwriter_traverse
, /* tp_traverse */
1712 0, /* tp_richcompare */
1713 0, /* tp_weaklistoffset */
1716 mbstreamwriter_methods
, /* tp_methods */
1717 mbstreamwriter_members
, /* tp_members */
1718 codecctx_getsets
, /* tp_getset */
1721 0, /* tp_descr_get */
1722 0, /* tp_descr_set */
1723 0, /* tp_dictoffset */
1724 mbstreamwriter_init
, /* tp_init */
1726 mbstreamwriter_new
, /* tp_new */
1731 * Exposed factory function
1735 __create_codec(PyObject
*ignore
, PyObject
*arg
)
1737 MultibyteCodecObject
*self
;
1738 MultibyteCodec
*codec
;
1740 if (!PyCObject_Check(arg
)) {
1741 PyErr_SetString(PyExc_ValueError
, "argument type invalid");
1745 codec
= PyCObject_AsVoidPtr(arg
);
1746 if (codec
->codecinit
!= NULL
&& codec
->codecinit(codec
->config
) != 0)
1749 self
= PyObject_New(MultibyteCodecObject
, &MultibyteCodec_Type
);
1752 self
->codec
= codec
;
1754 return (PyObject
*)self
;
1757 static struct PyMethodDef __methods
[] = {
1758 {"__create_codec", (PyCFunction
)__create_codec
, METH_O
},
1763 init_multibytecodec(void)
1767 PyTypeObject
*typelist
[] = {
1768 &MultibyteIncrementalEncoder_Type
,
1769 &MultibyteIncrementalDecoder_Type
,
1770 &MultibyteStreamReader_Type
,
1771 &MultibyteStreamWriter_Type
,
1775 if (PyType_Ready(&MultibyteCodec_Type
) < 0)
1778 m
= Py_InitModule("_multibytecodec", __methods
);
1782 for (i
= 0; typelist
[i
] != NULL
; i
++) {
1783 if (PyType_Ready(typelist
[i
]) < 0)
1785 Py_INCREF(typelist
[i
]);
1786 PyModule_AddObject(m
, typelist
[i
]->tp_name
,
1787 (PyObject
*)typelist
[i
]);
1790 if (PyErr_Occurred())
1791 Py_FatalError("can't initialize the _multibytecodec module");