Branch data Line data Source code
1 : : /*
2 : : * cjkcodecs.h: common header for cjkcodecs
3 : : *
4 : : * Written by Hye-Shik Chang <perky@FreeBSD.org>
5 : : */
6 : :
7 : : #ifndef _CJKCODECS_H_
8 : : #define _CJKCODECS_H_
9 : :
10 : : #define PY_SSIZE_T_CLEAN
11 : : #include "Python.h"
12 : : #include "multibytecodec.h"
13 : :
14 : :
15 : : /* a unicode "undefined" code point */
16 : : #define UNIINV 0xFFFE
17 : :
18 : : /* internal-use DBCS code points which aren't used by any charsets */
19 : : #define NOCHAR 0xFFFF
20 : : #define MULTIC 0xFFFE
21 : : #define DBCINV 0xFFFD
22 : :
23 : : /* shorter macros to save source size of mapping tables */
24 : : #define U UNIINV
25 : : #define N NOCHAR
26 : : #define M MULTIC
27 : : #define D DBCINV
28 : :
29 : : struct dbcs_index {
30 : : const ucs2_t *map;
31 : : unsigned char bottom, top;
32 : : };
33 : : typedef struct dbcs_index decode_map;
34 : :
35 : : struct widedbcs_index {
36 : : const Py_UCS4 *map;
37 : : unsigned char bottom, top;
38 : : };
39 : : typedef struct widedbcs_index widedecode_map;
40 : :
41 : : struct unim_index {
42 : : const DBCHAR *map;
43 : : unsigned char bottom, top;
44 : : };
45 : : typedef struct unim_index encode_map;
46 : :
47 : : struct unim_index_bytebased {
48 : : const unsigned char *map;
49 : : unsigned char bottom, top;
50 : : };
51 : :
52 : : struct dbcs_map {
53 : : const char *charset;
54 : : const struct unim_index *encmap;
55 : : const struct dbcs_index *decmap;
56 : : };
57 : :
58 : : struct pair_encodemap {
59 : : Py_UCS4 uniseq;
60 : : DBCHAR code;
61 : : };
62 : :
63 : : static const MultibyteCodec *codec_list;
64 : : static const struct dbcs_map *mapping_list;
65 : :
66 : : #define CODEC_INIT(encoding) \
67 : : static int encoding##_codec_init(const void *config)
68 : :
69 : : #define ENCODER_INIT(encoding) \
70 : : static int encoding##_encode_init( \
71 : : MultibyteCodec_State *state, const void *config)
72 : : #define ENCODER(encoding) \
73 : : static Py_ssize_t encoding##_encode( \
74 : : MultibyteCodec_State *state, const void *config, \
75 : : int kind, const void *data, \
76 : : Py_ssize_t *inpos, Py_ssize_t inlen, \
77 : : unsigned char **outbuf, Py_ssize_t outleft, int flags)
78 : : #define ENCODER_RESET(encoding) \
79 : : static Py_ssize_t encoding##_encode_reset( \
80 : : MultibyteCodec_State *state, const void *config, \
81 : : unsigned char **outbuf, Py_ssize_t outleft)
82 : :
83 : : #define DECODER_INIT(encoding) \
84 : : static int encoding##_decode_init( \
85 : : MultibyteCodec_State *state, const void *config)
86 : : #define DECODER(encoding) \
87 : : static Py_ssize_t encoding##_decode( \
88 : : MultibyteCodec_State *state, const void *config, \
89 : : const unsigned char **inbuf, Py_ssize_t inleft, \
90 : : _PyUnicodeWriter *writer)
91 : : #define DECODER_RESET(encoding) \
92 : : static Py_ssize_t encoding##_decode_reset( \
93 : : MultibyteCodec_State *state, const void *config)
94 : :
95 : : #define NEXT_IN(i) \
96 : : do { \
97 : : (*inbuf) += (i); \
98 : : (inleft) -= (i); \
99 : : } while (0)
100 : : #define NEXT_INCHAR(i) \
101 : : do { \
102 : : (*inpos) += (i); \
103 : : } while (0)
104 : : #define NEXT_OUT(o) \
105 : : do { \
106 : : (*outbuf) += (o); \
107 : : (outleft) -= (o); \
108 : : } while (0)
109 : : #define NEXT(i, o) \
110 : : do { \
111 : : NEXT_INCHAR(i); \
112 : : NEXT_OUT(o); \
113 : : } while (0)
114 : :
115 : : #define REQUIRE_INBUF(n) \
116 : : do { \
117 : : if (inleft < (n)) \
118 : : return MBERR_TOOFEW; \
119 : : } while (0)
120 : :
121 : : #define REQUIRE_OUTBUF(n) \
122 : : do { \
123 : : if (outleft < (n)) \
124 : : return MBERR_TOOSMALL; \
125 : : } while (0)
126 : :
127 : : #define INBYTE1 ((*inbuf)[0])
128 : : #define INBYTE2 ((*inbuf)[1])
129 : : #define INBYTE3 ((*inbuf)[2])
130 : : #define INBYTE4 ((*inbuf)[3])
131 : :
132 : : #define INCHAR1 (PyUnicode_READ(kind, data, *inpos))
133 : : #define INCHAR2 (PyUnicode_READ(kind, data, *inpos + 1))
134 : :
135 : : #define OUTCHAR(c) \
136 : : do { \
137 : : if (_PyUnicodeWriter_WriteChar(writer, (c)) < 0) \
138 : : return MBERR_EXCEPTION; \
139 : : } while (0)
140 : :
141 : : #define OUTCHAR2(c1, c2) \
142 : : do { \
143 : : Py_UCS4 _c1 = (c1); \
144 : : Py_UCS4 _c2 = (c2); \
145 : : if (_PyUnicodeWriter_Prepare(writer, 2, Py_MAX(_c1, c2)) < 0) \
146 : : return MBERR_EXCEPTION; \
147 : : PyUnicode_WRITE(writer->kind, writer->data, writer->pos, _c1); \
148 : : PyUnicode_WRITE(writer->kind, writer->data, writer->pos + 1, _c2); \
149 : : writer->pos += 2; \
150 : : } while (0)
151 : :
152 : : #define OUTBYTEI(c, i) \
153 : : do { \
154 : : assert((unsigned char)(c) == (c)); \
155 : : ((*outbuf)[i]) = (c); \
156 : : } while (0)
157 : :
158 : : #define OUTBYTE1(c) OUTBYTEI(c, 0)
159 : : #define OUTBYTE2(c) OUTBYTEI(c, 1)
160 : : #define OUTBYTE3(c) OUTBYTEI(c, 2)
161 : : #define OUTBYTE4(c) OUTBYTEI(c, 3)
162 : :
163 : : #define WRITEBYTE1(c1) \
164 : : do { \
165 : : REQUIRE_OUTBUF(1); \
166 : : OUTBYTE1(c1); \
167 : : } while (0)
168 : : #define WRITEBYTE2(c1, c2) \
169 : : do { \
170 : : REQUIRE_OUTBUF(2); \
171 : : OUTBYTE1(c1); \
172 : : OUTBYTE2(c2); \
173 : : } while (0)
174 : : #define WRITEBYTE3(c1, c2, c3) \
175 : : do { \
176 : : REQUIRE_OUTBUF(3); \
177 : : OUTBYTE1(c1); \
178 : : OUTBYTE2(c2); \
179 : : OUTBYTE3(c3); \
180 : : } while (0)
181 : : #define WRITEBYTE4(c1, c2, c3, c4) \
182 : : do { \
183 : : REQUIRE_OUTBUF(4); \
184 : : OUTBYTE1(c1); \
185 : : OUTBYTE2(c2); \
186 : : OUTBYTE3(c3); \
187 : : OUTBYTE4(c4); \
188 : : } while (0)
189 : :
190 : : #define _TRYMAP_ENC(m, assi, val) \
191 : : ((m)->map != NULL && (val) >= (m)->bottom && \
192 : : (val)<= (m)->top && ((assi) = (m)->map[(val) - \
193 : : (m)->bottom]) != NOCHAR)
194 : : #define TRYMAP_ENC(charset, assi, uni) \
195 : : _TRYMAP_ENC(&charset##_encmap[(uni) >> 8], assi, (uni) & 0xff)
196 : :
197 : : #define _TRYMAP_DEC(m, assi, val) \
198 : : ((m)->map != NULL && \
199 : : (val) >= (m)->bottom && \
200 : : (val)<= (m)->top && \
201 : : ((assi) = (m)->map[(val) - (m)->bottom]) != UNIINV)
202 : : #define TRYMAP_DEC(charset, assi, c1, c2) \
203 : : _TRYMAP_DEC(&charset##_decmap[c1], assi, c2)
204 : :
205 : : #define BEGIN_MAPPINGS_LIST static const struct dbcs_map _mapping_list[] = {
206 : : #define MAPPING_ENCONLY(enc) {#enc, (void*)enc##_encmap, NULL},
207 : : #define MAPPING_DECONLY(enc) {#enc, NULL, (void*)enc##_decmap},
208 : : #define MAPPING_ENCDEC(enc) {#enc, (void*)enc##_encmap, (void*)enc##_decmap},
209 : : #define END_MAPPINGS_LIST \
210 : : {"", NULL, NULL} }; \
211 : : static const struct dbcs_map *mapping_list = \
212 : : (const struct dbcs_map *)_mapping_list;
213 : :
214 : : #define BEGIN_CODECS_LIST static const MultibyteCodec _codec_list[] = {
215 : : #define _STATEFUL_METHODS(enc) \
216 : : enc##_encode, \
217 : : enc##_encode_init, \
218 : : enc##_encode_reset, \
219 : : enc##_decode, \
220 : : enc##_decode_init, \
221 : : enc##_decode_reset,
222 : : #define _STATELESS_METHODS(enc) \
223 : : enc##_encode, NULL, NULL, \
224 : : enc##_decode, NULL, NULL,
225 : : #define CODEC_STATEFUL(enc) { \
226 : : #enc, NULL, NULL, \
227 : : _STATEFUL_METHODS(enc) \
228 : : },
229 : : #define CODEC_STATELESS(enc) { \
230 : : #enc, NULL, NULL, \
231 : : _STATELESS_METHODS(enc) \
232 : : },
233 : : #define CODEC_STATELESS_WINIT(enc) { \
234 : : #enc, NULL, \
235 : : enc##_codec_init, \
236 : : _STATELESS_METHODS(enc) \
237 : : },
238 : : #define END_CODECS_LIST \
239 : : {"", NULL,} }; \
240 : : static const MultibyteCodec *codec_list = \
241 : : (const MultibyteCodec *)_codec_list;
242 : :
243 : :
244 : :
245 : : static PyObject *
246 : 142 : getmultibytecodec(void)
247 : : {
248 : 142 : return _PyImport_GetModuleAttrString("_multibytecodec", "__create_codec");
249 : : }
250 : :
251 : : static PyObject *
252 : 142 : getcodec(PyObject *self, PyObject *encoding)
253 : : {
254 : : PyObject *codecobj, *r, *cofunc;
255 : : const MultibyteCodec *codec;
256 : : const char *enc;
257 : :
258 [ - + ]: 142 : if (!PyUnicode_Check(encoding)) {
259 : 0 : PyErr_SetString(PyExc_TypeError,
260 : : "encoding name must be a string.");
261 : 0 : return NULL;
262 : : }
263 : 142 : enc = PyUnicode_AsUTF8(encoding);
264 [ - + ]: 142 : if (enc == NULL)
265 : 0 : return NULL;
266 : :
267 : 142 : cofunc = getmultibytecodec();
268 [ - + ]: 142 : if (cofunc == NULL)
269 : 0 : return NULL;
270 : :
271 [ + - ]: 421 : for (codec = codec_list; codec->encoding[0]; codec++)
272 [ + + ]: 421 : if (strcmp(codec->encoding, enc) == 0)
273 : 142 : break;
274 : :
275 [ - + ]: 142 : if (codec->encoding[0] == '\0') {
276 : 0 : PyErr_SetString(PyExc_LookupError,
277 : : "no such codec is supported.");
278 : 0 : return NULL;
279 : : }
280 : :
281 : 142 : codecobj = PyCapsule_New((void *)codec, PyMultibyteCodec_CAPSULE_NAME, NULL);
282 [ - + ]: 142 : if (codecobj == NULL)
283 : 0 : return NULL;
284 : :
285 : 142 : r = PyObject_CallOneArg(cofunc, codecobj);
286 : 142 : Py_DECREF(codecobj);
287 : 142 : Py_DECREF(cofunc);
288 : :
289 : 142 : return r;
290 : : }
291 : :
292 : :
293 : : static int
294 : 58 : register_maps(PyObject *module)
295 : : {
296 : : const struct dbcs_map *h;
297 : :
298 [ + + ]: 319 : for (h = mapping_list; h->charset[0] != '\0'; h++) {
299 : 261 : char mhname[256] = "__map_";
300 : 261 : strcpy(mhname + sizeof("__map_") - 1, h->charset);
301 : :
302 : 261 : PyObject *capsule = PyCapsule_New((void *)h,
303 : : PyMultibyteCodec_CAPSULE_NAME, NULL);
304 [ - + ]: 261 : if (capsule == NULL) {
305 : 0 : return -1;
306 : : }
307 [ - + ]: 261 : if (PyModule_AddObject(module, mhname, capsule) < 0) {
308 : 0 : Py_DECREF(capsule);
309 : 0 : return -1;
310 : : }
311 : : }
312 : 58 : return 0;
313 : : }
314 : :
315 : : #ifdef USING_BINARY_PAIR_SEARCH
316 : : static DBCHAR
317 : 17503 : find_pairencmap(ucs2_t body, ucs2_t modifier,
318 : : const struct pair_encodemap *haystack, int haystacksize)
319 : : {
320 : : int pos, min, max;
321 : 17503 : Py_UCS4 value = body << 16 | modifier;
322 : :
323 : 17503 : min = 0;
324 : 17503 : max = haystacksize;
325 : :
326 [ + - ]: 104028 : for (pos = haystacksize >> 1; min != max; pos = (min + max) >> 1) {
327 [ + + ]: 104028 : if (value < haystack[pos].uniseq) {
328 [ + - ]: 35037 : if (max != pos) {
329 : 35037 : max = pos;
330 : 35037 : continue;
331 : : }
332 : : }
333 [ + + ]: 68991 : else if (value > haystack[pos].uniseq) {
334 [ + + ]: 59753 : if (min != pos) {
335 : 51488 : min = pos;
336 : 51488 : continue;
337 : : }
338 : : }
339 : 17503 : break;
340 : : }
341 : :
342 [ + + ]: 17503 : if (value == haystack[pos].uniseq) {
343 : 9238 : return haystack[pos].code;
344 : : }
345 : 8265 : return DBCINV;
346 : : }
347 : : #endif
348 : :
349 : : #ifdef USING_IMPORTED_MAPS
350 : : #define IMPORT_MAP(locale, charset, encmap, decmap) \
351 : : importmap("_codecs_" #locale, "__map_" #charset, \
352 : : (const void**)encmap, (const void**)decmap)
353 : :
354 : : static int
355 : 76 : importmap(const char *modname, const char *symbol,
356 : : const void **encmap, const void **decmap)
357 : : {
358 : : PyObject *o, *mod;
359 : :
360 : 76 : mod = PyImport_ImportModule(modname);
361 [ - + ]: 76 : if (mod == NULL)
362 : 0 : return -1;
363 : :
364 : 76 : o = PyObject_GetAttrString(mod, symbol);
365 [ - + ]: 76 : if (o == NULL)
366 : 0 : goto errorexit;
367 [ - + ]: 76 : else if (!PyCapsule_IsValid(o, PyMultibyteCodec_CAPSULE_NAME)) {
368 : 0 : PyErr_SetString(PyExc_ValueError,
369 : : "map data must be a Capsule.");
370 : 0 : goto errorexit;
371 : : }
372 : : else {
373 : : struct dbcs_map *map;
374 : 76 : map = PyCapsule_GetPointer(o, PyMultibyteCodec_CAPSULE_NAME);
375 [ + + ]: 76 : if (encmap != NULL)
376 : 39 : *encmap = map->encmap;
377 [ + + ]: 76 : if (decmap != NULL)
378 : 47 : *decmap = map->decmap;
379 : 76 : Py_DECREF(o);
380 : : }
381 : :
382 : 76 : Py_DECREF(mod);
383 : 76 : return 0;
384 : :
385 : 0 : errorexit:
386 : 0 : Py_DECREF(mod);
387 : 0 : return -1;
388 : : }
389 : : #endif
390 : :
391 : : static int
392 : 58 : _cjk_exec(PyObject *module)
393 : : {
394 : 58 : return register_maps(module);
395 : : }
396 : :
397 : :
398 : : static struct PyMethodDef _cjk_methods[] = {
399 : : {"getcodec", (PyCFunction)getcodec, METH_O, ""},
400 : : {NULL, NULL},
401 : : };
402 : :
403 : : static PyModuleDef_Slot _cjk_slots[] = {
404 : : {Py_mod_exec, _cjk_exec},
405 : : {0, NULL}
406 : : };
407 : :
408 : : #define I_AM_A_MODULE_FOR(loc) \
409 : : static struct PyModuleDef _cjk_module = { \
410 : : PyModuleDef_HEAD_INIT, \
411 : : .m_name = "_codecs_"#loc, \
412 : : .m_size = 0, \
413 : : .m_methods = _cjk_methods, \
414 : : .m_slots = _cjk_slots, \
415 : : }; \
416 : : \
417 : : PyMODINIT_FUNC \
418 : : PyInit__codecs_##loc(void) \
419 : : { \
420 : : return PyModuleDef_Init(&_cjk_module); \
421 : : }
422 : :
423 : : #endif
|