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