/src/dcmtk/oficonv/libsrc/citrus_iso2022.c
Line | Count | Source |
1 | | /*- |
2 | | * Copyright (c)1999, 2002 Citrus Project, |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
15 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
17 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
18 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
19 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
20 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
21 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
22 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
23 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
24 | | * SUCH DAMAGE. |
25 | | * |
26 | | */ |
27 | | |
28 | | #include "dcmtk/config/osconfig.h" |
29 | | #include "citrus_iso2022.h" |
30 | | |
31 | | #include <sys/types.h> |
32 | | #include <errno.h> |
33 | | #include <limits.h> |
34 | | #include <stdbool.h> |
35 | | #include <stddef.h> |
36 | | #include <stdio.h> |
37 | | #include <stdlib.h> |
38 | | #include <string.h> |
39 | | #include <wchar.h> |
40 | | |
41 | | #include "citrus_bcs.h" |
42 | | #include "citrus_types.h" |
43 | | #include "citrus_module.h" |
44 | | #include "citrus_stdenc.h" |
45 | | |
46 | | |
47 | | /* ---------------------------------------------------------------------- |
48 | | * private stuffs used by templates |
49 | | */ |
50 | | |
51 | | |
52 | | /* |
53 | | * _citrus_wc_t mappings: |
54 | | * ASCII (ESC ( B) 00000000 00000000 00000000 0xxxxxxx |
55 | | * iso-8859-1 (ESC , A) 00000000 00000000 00000000 1xxxxxxx |
56 | | * 94 charset (ESC ( F) 0fffffff 00000000 00000000 0xxxxxxx |
57 | | * 94 charset (ESC ( M F) 0fffffff 1mmmmmmm 00000000 0xxxxxxx |
58 | | * 96 charset (ESC , F) 0fffffff 00000000 00000000 1xxxxxxx |
59 | | * 96 charset (ESC , M F) 0fffffff 1mmmmmmm 00000000 1xxxxxxx |
60 | | * 94x94 charset (ESC $ ( F) 0fffffff 00000000 0xxxxxxx 0xxxxxxx |
61 | | * 96x96 charset (ESC $ , F) 0fffffff 00000000 0xxxxxxx 1xxxxxxx |
62 | | * 94x94 charset (ESC & V ESC $ ( F) |
63 | | * 0fffffff 1vvvvvvv 0xxxxxxx 0xxxxxxx |
64 | | * 94x94x94 charset (ESC $ ( F) 0fffffff 0xxxxxxx 0xxxxxxx 0xxxxxxx |
65 | | * 96x96x96 charset (ESC $ , F) 0fffffff 0xxxxxxx 0xxxxxxx 1xxxxxxx |
66 | | * reserved for UCS4 co-existence (UCS4 is 31bit encoding thanks to mohta bit) |
67 | | * 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx |
68 | | */ |
69 | | |
70 | 0 | #define CS94 (0U) |
71 | 0 | #define CS96 (1U) |
72 | 0 | #define CS94MULTI (2U) |
73 | 0 | #define CS96MULTI (3U) |
74 | | |
75 | | typedef struct { |
76 | | unsigned char interm; |
77 | | unsigned char final; |
78 | | unsigned char type; |
79 | | unsigned char vers; |
80 | | } _ISO2022Charset; |
81 | | |
82 | | static const _ISO2022Charset ascii = { CS94, 'B', '\0', '\0' }; |
83 | | static const _ISO2022Charset iso88591 = { CS96, 'A', '\0', '\0' }; |
84 | | |
85 | | typedef struct { |
86 | | _ISO2022Charset g[4]; |
87 | | /* need 3 bits to hold -1, 0, ..., 3 */ |
88 | | int gl:3, |
89 | | gr:3, |
90 | | singlegl:3, |
91 | | singlegr:3; |
92 | | char ch[7]; /* longest escape sequence (ESC & V ESC $ ( F) */ |
93 | | size_t chlen; |
94 | | int flags; |
95 | 0 | #define _ISO2022STATE_FLAG_INITIALIZED 1 |
96 | | } _ISO2022State; |
97 | | |
98 | | typedef struct { |
99 | | _ISO2022Charset *recommend[4]; |
100 | | size_t recommendsize[4]; |
101 | | _ISO2022Charset initg[4]; |
102 | | int maxcharset; |
103 | | int flags; |
104 | 0 | #define F_8BIT 0x0001 |
105 | 0 | #define F_NOOLD 0x0002 |
106 | 0 | #define F_SI 0x0010 /*0F*/ |
107 | 0 | #define F_SO 0x0020 /*0E*/ |
108 | 0 | #define F_LS0 0x0010 /*0F*/ |
109 | 0 | #define F_LS1 0x0020 /*0E*/ |
110 | 0 | #define F_LS2 0x0040 /*ESC n*/ |
111 | 0 | #define F_LS3 0x0080 /*ESC o*/ |
112 | 0 | #define F_LS1R 0x0100 /*ESC ~*/ |
113 | 0 | #define F_LS2R 0x0200 /*ESC }*/ |
114 | 0 | #define F_LS3R 0x0400 /*ESC |*/ |
115 | 0 | #define F_SS2 0x0800 /*ESC N*/ |
116 | 0 | #define F_SS3 0x1000 /*ESC O*/ |
117 | 0 | #define F_SS2R 0x2000 /*8E*/ |
118 | 0 | #define F_SS3R 0x4000 /*8F*/ |
119 | | } _ISO2022EncodingInfo; |
120 | | |
121 | | #define _CEI_TO_EI(_cei_) (&(_cei_)->ei) |
122 | | #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_ |
123 | | |
124 | 0 | #define _FUNCNAME(m) _citrus_ISO2022_##m |
125 | 0 | #define _ENCODING_INFO _ISO2022EncodingInfo |
126 | | #define _ENCODING_STATE _ISO2022State |
127 | 0 | #define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX |
128 | 0 | #define _ENCODING_IS_STATE_DEPENDENT 1 |
129 | | #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) \ |
130 | | (!((_ps_)->flags & _ISO2022STATE_FLAG_INITIALIZED)) |
131 | | |
132 | | |
133 | 0 | #define _ISO2022INVALID (_citrus_wc_t)-1 |
134 | | |
135 | | static __inline bool isc0(uint8_t x) |
136 | 0 | { |
137 | |
|
138 | 0 | return ((x & 0x1f) == x); |
139 | 0 | } |
140 | | |
141 | | static __inline bool isc1(uint8_t x) |
142 | 0 | { |
143 | |
|
144 | 0 | return (0x80 <= x && x <= 0x9f); |
145 | 0 | } |
146 | | |
147 | | static __inline bool iscntl(uint8_t x) |
148 | 0 | { |
149 | |
|
150 | 0 | return (isc0(x) || isc1(x) || x == 0x7f); |
151 | 0 | } |
152 | | |
153 | | static __inline bool is94(uint8_t x) |
154 | 0 | { |
155 | |
|
156 | 0 | return (0x21 <= x && x <= 0x7e); |
157 | 0 | } |
158 | | |
159 | | static __inline bool is96(uint8_t x) |
160 | 0 | { |
161 | |
|
162 | 0 | return (0x20 <= x && x <= 0x7f); |
163 | 0 | } |
164 | | |
165 | | static __inline bool isecma(uint8_t x) |
166 | 0 | { |
167 | |
|
168 | 0 | return (0x30 <= x && x <= 0x7f); |
169 | 0 | } |
170 | | |
171 | | static __inline bool isinterm(uint8_t x) |
172 | 0 | { |
173 | |
|
174 | 0 | return (0x20 <= x && x <= 0x2f); |
175 | 0 | } |
176 | | |
177 | | static __inline bool isthree(uint8_t x) |
178 | 0 | { |
179 | |
|
180 | 0 | return (0x60 <= x && x <= 0x6f); |
181 | 0 | } |
182 | | |
183 | | static __inline int |
184 | | getcs(const char * p, _ISO2022Charset * cs) |
185 | 0 | { |
186 | |
|
187 | 0 | if (!strncmp(p, "94$", 3) && p[3] && !p[4]) { |
188 | 0 | cs->final = (unsigned char)(p[3] & 0xff); |
189 | 0 | cs->interm = '\0'; |
190 | 0 | cs->vers = '\0'; |
191 | 0 | cs->type = CS94MULTI; |
192 | 0 | } else if (!strncmp(p, "96$", 3) && p[3] && !p[4]) { |
193 | 0 | cs->final = (unsigned char)(p[3] & 0xff); |
194 | 0 | cs->interm = '\0'; |
195 | 0 | cs->vers = '\0'; |
196 | 0 | cs->type = CS96MULTI; |
197 | 0 | } else if (!strncmp(p, "94", 2) && p[2] && !p[3]) { |
198 | 0 | cs->final = (unsigned char)(p[2] & 0xff); |
199 | 0 | cs->interm = '\0'; |
200 | 0 | cs->vers = '\0'; |
201 | 0 | cs->type = CS94; |
202 | 0 | } else if (!strncmp(p, "96", 2) && p[2] && !p[3]) { |
203 | 0 | cs->final = (unsigned char )(p[2] & 0xff); |
204 | 0 | cs->interm = '\0'; |
205 | 0 | cs->vers = '\0'; |
206 | 0 | cs->type = CS96; |
207 | 0 | } else |
208 | 0 | return (1); |
209 | | |
210 | 0 | return (0); |
211 | 0 | } |
212 | | |
213 | | |
214 | 0 | #define _NOTMATCH 0 |
215 | 0 | #define _MATCH 1 |
216 | 0 | #define _PARSEFAIL 2 |
217 | | |
218 | | static __inline int |
219 | | get_recommend(_ISO2022EncodingInfo * ei, |
220 | | const char * token) |
221 | 0 | { |
222 | 0 | _ISO2022Charset cs, *p; |
223 | 0 | int i; |
224 | |
|
225 | 0 | if (!strchr("0123", token[0]) || token[1] != '=') |
226 | 0 | return (_NOTMATCH); |
227 | | |
228 | 0 | if (getcs(&token[2], &cs) == 0) |
229 | 0 | ; |
230 | 0 | else if (!strcmp(&token[2], "94")) { |
231 | 0 | cs.final = (unsigned char)(token[4]); |
232 | 0 | cs.interm = '\0'; |
233 | 0 | cs.vers = '\0'; |
234 | 0 | cs.type = CS94; |
235 | 0 | } else if (!strcmp(&token[2], "96")) { |
236 | 0 | cs.final = (unsigned char)(token[4]); |
237 | 0 | cs.interm = '\0'; |
238 | 0 | cs.vers = '\0'; |
239 | 0 | cs.type = CS96; |
240 | 0 | } else if (!strcmp(&token[2], "94$")) { |
241 | 0 | cs.final = (unsigned char)(token[5]); |
242 | 0 | cs.interm = '\0'; |
243 | 0 | cs.vers = '\0'; |
244 | 0 | cs.type = CS94MULTI; |
245 | 0 | } else if (!strcmp(&token[2], "96$")) { |
246 | 0 | cs.final = (unsigned char)(token[5]); |
247 | 0 | cs.interm = '\0'; |
248 | 0 | cs.vers = '\0'; |
249 | 0 | cs.type = CS96MULTI; |
250 | 0 | } else |
251 | 0 | return (_PARSEFAIL); |
252 | | |
253 | 0 | i = token[0] - '0'; |
254 | 0 | if (!ei->recommend[i]) |
255 | 0 | ei->recommend[i] = malloc(sizeof(_ISO2022Charset)); |
256 | 0 | else { |
257 | 0 | p = realloc(ei->recommend[i], (ei->recommendsize[i] + 1) * sizeof(_ISO2022Charset)); |
258 | |
|
259 | 0 | if (!p) |
260 | 0 | return (_PARSEFAIL); |
261 | 0 | ei->recommend[i] = p; |
262 | 0 | } |
263 | 0 | if (!ei->recommend[i]) |
264 | 0 | return (_PARSEFAIL); |
265 | 0 | ei->recommendsize[i]++; |
266 | |
|
267 | 0 | (ei->recommend[i] + (ei->recommendsize[i] - 1))->final = cs.final; |
268 | 0 | (ei->recommend[i] + (ei->recommendsize[i] - 1))->interm = cs.interm; |
269 | 0 | (ei->recommend[i] + (ei->recommendsize[i] - 1))->vers = cs.vers; |
270 | 0 | (ei->recommend[i] + (ei->recommendsize[i] - 1))->type = cs.type; |
271 | |
|
272 | 0 | return (_MATCH); |
273 | 0 | } |
274 | | |
275 | | static __inline int |
276 | | get_initg(_ISO2022EncodingInfo * ei, |
277 | | const char * token) |
278 | 0 | { |
279 | 0 | _ISO2022Charset cs; |
280 | |
|
281 | 0 | if (strncmp("INIT", &token[0], 4) || |
282 | 0 | !strchr("0123", token[4]) || |
283 | 0 | token[5] != '=') |
284 | 0 | return (_NOTMATCH); |
285 | | |
286 | 0 | if (getcs(&token[6], &cs) != 0) |
287 | 0 | return (_PARSEFAIL); |
288 | | |
289 | | /* suppress spurious GCC warnings */ |
290 | | #if ( defined(__GNUC__) && (__GNUC__ >= 10) ) |
291 | | #pragma GCC diagnostic push |
292 | | #pragma GCC diagnostic ignored "-Wstringop-overflow" |
293 | | #endif |
294 | | |
295 | 0 | ei->initg[token[4] - '0'].type = cs.type; |
296 | 0 | ei->initg[token[4] - '0'].final = cs.final; |
297 | 0 | ei->initg[token[4] - '0'].interm = cs.interm; |
298 | 0 | ei->initg[token[4] - '0'].vers = cs.vers; |
299 | |
|
300 | | #if ( defined(__GNUC__) && (__GNUC__ >= 10) ) |
301 | | #pragma GCC diagnostic pop |
302 | | #endif |
303 | |
|
304 | 0 | return (_MATCH); |
305 | 0 | } |
306 | | |
307 | | static __inline int |
308 | | get_max(_ISO2022EncodingInfo * ei, |
309 | | const char * token) |
310 | 0 | { |
311 | 0 | if (!strcmp(token, "MAX1")) |
312 | 0 | ei->maxcharset = 1; |
313 | 0 | else if (!strcmp(token, "MAX2")) |
314 | 0 | ei->maxcharset = 2; |
315 | 0 | else if (!strcmp(token, "MAX3")) |
316 | 0 | ei->maxcharset = 3; |
317 | 0 | else |
318 | 0 | return (_NOTMATCH); |
319 | | |
320 | 0 | return (_MATCH); |
321 | 0 | } |
322 | | |
323 | | |
324 | | static __inline int |
325 | | get_flags(_ISO2022EncodingInfo * ei, |
326 | | const char * token) |
327 | 0 | { |
328 | 0 | static struct { |
329 | 0 | const char *tag; |
330 | 0 | int flag; |
331 | 0 | } const tags[] = { |
332 | 0 | { "DUMMY", 0 }, |
333 | 0 | { "8BIT", F_8BIT }, |
334 | 0 | { "NOOLD", F_NOOLD }, |
335 | 0 | { "SI", F_SI }, |
336 | 0 | { "SO", F_SO }, |
337 | 0 | { "LS0", F_LS0 }, |
338 | 0 | { "LS1", F_LS1 }, |
339 | 0 | { "LS2", F_LS2 }, |
340 | 0 | { "LS3", F_LS3 }, |
341 | 0 | { "LS1R", F_LS1R }, |
342 | 0 | { "LS2R", F_LS2R }, |
343 | 0 | { "LS3R", F_LS3R }, |
344 | 0 | { "SS2", F_SS2 }, |
345 | 0 | { "SS3", F_SS3 }, |
346 | 0 | { "SS2R", F_SS2R }, |
347 | 0 | { "SS3R", F_SS3R }, |
348 | 0 | { NULL, 0 } |
349 | 0 | }; |
350 | 0 | int i; |
351 | |
|
352 | 0 | for (i = 0; tags[i].tag; i++) |
353 | 0 | if (!strcmp(token, tags[i].tag)) { |
354 | 0 | ei->flags |= tags[i].flag; |
355 | 0 | return (_MATCH); |
356 | 0 | } |
357 | | |
358 | 0 | return (_NOTMATCH); |
359 | 0 | } |
360 | | |
361 | | |
362 | | static __inline int |
363 | | _citrus_ISO2022_parse_variable(_ISO2022EncodingInfo * ei, |
364 | | const void * var, size_t lenvar ) |
365 | 0 | { |
366 | 0 | char const *e, *v; |
367 | 0 | char buf[20]; |
368 | 0 | size_t len; |
369 | 0 | int i, ret; |
370 | 0 | (void) lenvar; |
371 | | |
372 | | /* |
373 | | * parse VARIABLE section. |
374 | | */ |
375 | |
|
376 | 0 | if (!var) |
377 | 0 | return (EFTYPE); |
378 | | |
379 | 0 | v = (const char *) var; |
380 | | |
381 | | /* initialize structure */ |
382 | 0 | ei->maxcharset = 0; |
383 | 0 | for (i = 0; i < 4; i++) { |
384 | 0 | ei->recommend[i] = NULL; |
385 | 0 | ei->recommendsize[i] = 0; |
386 | 0 | } |
387 | 0 | ei->flags = 0; |
388 | |
|
389 | 0 | while (*v) { |
390 | 0 | while (*v == ' ' || *v == '\t') |
391 | 0 | ++v; |
392 | | |
393 | | /* find the token */ |
394 | 0 | e = v; |
395 | 0 | while (*e && *e != ' ' && *e != '\t') |
396 | 0 | ++e; |
397 | |
|
398 | 0 | len = e - v; |
399 | 0 | if (len == 0) |
400 | 0 | break; |
401 | 0 | if (len >= sizeof(buf)) |
402 | 0 | goto parsefail; |
403 | 0 | snprintf(buf, sizeof(buf), "%.*s", (int)len, v); |
404 | |
|
405 | 0 | if ((ret = get_recommend(ei, buf)) != _NOTMATCH) |
406 | 0 | ; |
407 | 0 | else if ((ret = get_initg(ei, buf)) != _NOTMATCH) |
408 | 0 | ; |
409 | 0 | else if ((ret = get_max(ei, buf)) != _NOTMATCH) |
410 | 0 | ; |
411 | 0 | else if ((ret = get_flags(ei, buf)) != _NOTMATCH) |
412 | 0 | ; |
413 | 0 | else |
414 | 0 | ret = _PARSEFAIL; |
415 | 0 | if (ret == _PARSEFAIL) |
416 | 0 | goto parsefail; |
417 | 0 | v = e; |
418 | |
|
419 | 0 | } |
420 | | |
421 | 0 | return (0); |
422 | | |
423 | 0 | parsefail: |
424 | 0 | free(ei->recommend[0]); |
425 | 0 | free(ei->recommend[1]); |
426 | 0 | free(ei->recommend[2]); |
427 | 0 | free(ei->recommend[3]); |
428 | |
|
429 | 0 | return (EFTYPE); |
430 | 0 | } |
431 | | |
432 | | static __inline void |
433 | | /*ARGSUSED*/ |
434 | | _citrus_ISO2022_init_state(_ISO2022EncodingInfo * ei, |
435 | | _ISO2022State * s) |
436 | 0 | { |
437 | 0 | int i; |
438 | |
|
439 | 0 | memset(s, 0, sizeof(*s)); |
440 | 0 | s->gl = 0; |
441 | 0 | s->gr = (ei->flags & F_8BIT) ? 1 : -1; |
442 | |
|
443 | 0 | for (i = 0; i < 4; i++) |
444 | 0 | if (ei->initg[i].final) { |
445 | 0 | s->g[i].type = ei->initg[i].type; |
446 | 0 | s->g[i].final = ei->initg[i].final; |
447 | 0 | s->g[i].interm = ei->initg[i].interm; |
448 | 0 | } |
449 | 0 | s->singlegl = s->singlegr = -1; |
450 | 0 | s->flags |= _ISO2022STATE_FLAG_INITIALIZED; |
451 | 0 | } |
452 | | |
453 | | static int |
454 | | /*ARGSUSED*/ |
455 | | _citrus_ISO2022_encoding_module_init(_ISO2022EncodingInfo * ei, |
456 | | const void * var, size_t lenvar) |
457 | 0 | { |
458 | |
|
459 | 0 | return (_citrus_ISO2022_parse_variable(ei, var, lenvar)); |
460 | 0 | } |
461 | | |
462 | | static void |
463 | | /*ARGSUSED*/ |
464 | | _citrus_ISO2022_encoding_module_uninit(_ISO2022EncodingInfo *ei ) |
465 | 0 | { |
466 | 0 | (void) ei; |
467 | 0 | } |
468 | | |
469 | | #define ESC '\033' |
470 | 0 | #define ECMA -1 |
471 | 0 | #define INTERM -2 |
472 | 0 | #define OECMA -3 |
473 | | static const struct seqtable { |
474 | | int type; |
475 | | int csoff; |
476 | | int finaloff; |
477 | | int intermoff; |
478 | | int versoff; |
479 | | int len; |
480 | | int chars[10]; |
481 | | } seqtable[] = { |
482 | | /* G0 94MULTI special */ |
483 | | { CS94MULTI, -1, 2, -1, -1, 3, { ESC, '$', OECMA }, }, |
484 | | /* G0 94MULTI special with version identification */ |
485 | | { CS94MULTI, -1, 5, -1, 2, 6, { ESC, '&', ECMA, ESC, '$', OECMA }, }, |
486 | | /* G? 94 */ |
487 | | { CS94, 1, 2, -1, -1, 3, { ESC, CS94, ECMA, }, }, |
488 | | /* G? 94 with 2nd intermediate char */ |
489 | | { CS94, 1, 3, 2, -1, 4, { ESC, CS94, INTERM, ECMA, }, }, |
490 | | /* G? 96 */ |
491 | | { CS96, 1, 2, -1, -1, 3, { ESC, CS96, ECMA, }, }, |
492 | | /* G? 96 with 2nd intermediate char */ |
493 | | { CS96, 1, 3, 2, -1, 4, { ESC, CS96, INTERM, ECMA, }, }, |
494 | | /* G? 94MULTI */ |
495 | | { CS94MULTI, 2, 3, -1, -1, 4, { ESC, '$', CS94, ECMA, }, }, |
496 | | /* G? 96MULTI */ |
497 | | { CS96MULTI, 2, 3, -1, -1, 4, { ESC, '$', CS96, ECMA, }, }, |
498 | | /* G? 94MULTI with version specification */ |
499 | | { CS94MULTI, 5, 6, -1, 2, 7, { ESC, '&', ECMA, ESC, '$', CS94, ECMA, }, }, |
500 | | /* LS2/3 */ |
501 | | { -1, -1, -1, -1, -1, 2, { ESC, 'n', }, }, |
502 | | { -1, -1, -1, -1, -1, 2, { ESC, 'o', }, }, |
503 | | /* LS1/2/3R */ |
504 | | { -1, -1, -1, -1, -1, 2, { ESC, '~', }, }, |
505 | | { -1, -1, -1, -1, -1, 2, { ESC, /*{*/ '}', }, }, |
506 | | { -1, -1, -1, -1, -1, 2, { ESC, '|', }, }, |
507 | | /* SS2/3 */ |
508 | | { -1, -1, -1, -1, -1, 2, { ESC, 'N', }, }, |
509 | | { -1, -1, -1, -1, -1, 2, { ESC, 'O', }, }, |
510 | | /* end of records */ |
511 | | /* { 0, } */ |
512 | | { 0, 0, 0, 0, 0, 0, { ESC, 0, }, } |
513 | | }; |
514 | | |
515 | | static int |
516 | | seqmatch(const char * s, size_t n, |
517 | | const struct seqtable * sp) |
518 | 0 | { |
519 | 0 | const int *p; |
520 | |
|
521 | 0 | p = sp->chars; |
522 | 0 | while ((size_t)(p - sp->chars) < n && p - sp->chars < sp->len) { |
523 | 0 | switch (*p) { |
524 | 0 | case ECMA: |
525 | 0 | if (!isecma(*s)) |
526 | 0 | goto terminate; |
527 | 0 | break; |
528 | 0 | case OECMA: |
529 | 0 | if (*s && strchr("@AB", *s)) |
530 | 0 | break; |
531 | 0 | else |
532 | 0 | goto terminate; |
533 | 0 | case INTERM: |
534 | 0 | if (!isinterm(*s)) |
535 | 0 | goto terminate; |
536 | 0 | break; |
537 | 0 | case CS94: |
538 | 0 | if (*s && strchr("()*+", *s)) |
539 | 0 | break; |
540 | 0 | else |
541 | 0 | goto terminate; |
542 | 0 | case CS96: |
543 | 0 | if (*s && strchr(",-./", *s)) |
544 | 0 | break; |
545 | 0 | else |
546 | 0 | goto terminate; |
547 | 0 | default: |
548 | 0 | if (*s != *p) |
549 | 0 | goto terminate; |
550 | 0 | break; |
551 | 0 | } |
552 | | |
553 | 0 | p++; |
554 | 0 | s++; |
555 | 0 | } |
556 | | |
557 | 0 | terminate: |
558 | 0 | return (int) (p - sp->chars); |
559 | 0 | } |
560 | | |
561 | | static _citrus_wc_t |
562 | | _ISO2022_sgetwchar(_ISO2022EncodingInfo * ei , |
563 | | char * string, size_t n, char ** result, |
564 | | _ISO2022State * psenc) |
565 | 0 | { |
566 | 0 | const struct seqtable *sp; |
567 | 0 | _citrus_wc_t wchar = 0; |
568 | 0 | int i, cur, nmatch; |
569 | 0 | (void) ei; |
570 | |
|
571 | 0 | while (1) { |
572 | | /* SI/SO */ |
573 | 0 | if (1 <= n && string[0] == '\017') { |
574 | 0 | psenc->gl = 0; |
575 | 0 | string++; |
576 | 0 | n--; |
577 | 0 | continue; |
578 | 0 | } |
579 | 0 | if (1 <= n && string[0] == '\016') { |
580 | 0 | psenc->gl = 1; |
581 | 0 | string++; |
582 | 0 | n--; |
583 | 0 | continue; |
584 | 0 | } |
585 | | |
586 | | /* SS2/3R */ |
587 | 0 | if (1 <= n && string[0] && strchr("\217\216", string[0])) { |
588 | 0 | psenc->singlegl = psenc->singlegr = |
589 | 0 | (string[0] - '\216') + 2; |
590 | 0 | string++; |
591 | 0 | n--; |
592 | 0 | continue; |
593 | 0 | } |
594 | | |
595 | | /* eat the letter if this is not ESC */ |
596 | 0 | if (1 <= n && string[0] != '\033') |
597 | 0 | break; |
598 | | |
599 | | /* look for a perfect match from escape sequences */ |
600 | 0 | for (sp = &seqtable[0]; sp->len; sp++) { |
601 | 0 | nmatch = seqmatch(string, n, sp); |
602 | 0 | if (sp->len == nmatch && n >= (size_t)(sp->len)) |
603 | 0 | break; |
604 | 0 | } |
605 | |
|
606 | 0 | if (!sp->len) |
607 | 0 | goto notseq; |
608 | | |
609 | 0 | if (sp->type != -1) { |
610 | 0 | if (sp->csoff == -1) |
611 | 0 | i = 0; |
612 | 0 | else { |
613 | 0 | switch (sp->type) { |
614 | 0 | case CS94: |
615 | 0 | case CS94MULTI: |
616 | 0 | i = string[sp->csoff] - '('; |
617 | 0 | break; |
618 | 0 | case CS96: |
619 | 0 | case CS96MULTI: |
620 | 0 | i = string[sp->csoff] - ','; |
621 | 0 | break; |
622 | 0 | default: |
623 | 0 | return (_ISO2022INVALID); |
624 | 0 | } |
625 | 0 | } |
626 | 0 | psenc->g[i].type = (unsigned char) sp->type; |
627 | 0 | psenc->g[i].final = '\0'; |
628 | 0 | psenc->g[i].interm = '\0'; |
629 | 0 | psenc->g[i].vers = '\0'; |
630 | | /* sp->finaloff must not be -1 */ |
631 | 0 | if (sp->finaloff != -1) |
632 | 0 | psenc->g[i].final = string[sp->finaloff]; |
633 | 0 | if (sp->intermoff != -1) |
634 | 0 | psenc->g[i].interm = string[sp->intermoff]; |
635 | 0 | if (sp->versoff != -1) |
636 | 0 | psenc->g[i].vers = string[sp->versoff]; |
637 | |
|
638 | 0 | string += sp->len; |
639 | 0 | n -= sp->len; |
640 | 0 | continue; |
641 | 0 | } |
642 | | |
643 | | /* LS2/3 */ |
644 | 0 | if (2 <= n && string[0] == '\033' && |
645 | 0 | string[1] && strchr("no", string[1])) { |
646 | 0 | psenc->gl = string[1] - 'n' + 2; |
647 | 0 | string += 2; |
648 | 0 | n -= 2; |
649 | 0 | continue; |
650 | 0 | } |
651 | | |
652 | | /* LS1/2/3R */ |
653 | | /* XXX: { for vi showmatch */ |
654 | 0 | if (2 <= n && string[0] == '\033' && |
655 | 0 | string[1] && strchr("~}|", string[1])) { |
656 | 0 | psenc->gr = 3 - (string[1] - '|'); |
657 | 0 | string += 2; |
658 | 0 | n -= 2; |
659 | 0 | continue; |
660 | 0 | } |
661 | | |
662 | | /* SS2/3 */ |
663 | 0 | if (2 <= n && string[0] == '\033' && string[1] && |
664 | 0 | strchr("NO", string[1])) { |
665 | 0 | psenc->singlegl = (string[1] - 'N') + 2; |
666 | 0 | string += 2; |
667 | 0 | n -= 2; |
668 | 0 | continue; |
669 | 0 | } |
670 | | |
671 | 0 | notseq: |
672 | | /* |
673 | | * if we've got an unknown escape sequence, eat the ESC at the |
674 | | * head. otherwise, wait till full escape sequence comes. |
675 | | */ |
676 | 0 | for (sp = &seqtable[0]; sp->len; sp++) { |
677 | 0 | nmatch = seqmatch(string, n, sp); |
678 | 0 | if (!nmatch) |
679 | 0 | continue; |
680 | | |
681 | | /* |
682 | | * if we are in the middle of escape sequence, |
683 | | * we still need to wait for more characters to come |
684 | | */ |
685 | 0 | if (n < (size_t)(sp->len)) { |
686 | 0 | if ((size_t)(nmatch) == n) { |
687 | 0 | if (result) |
688 | 0 | *result = string; |
689 | 0 | return (_ISO2022INVALID); |
690 | 0 | } |
691 | 0 | } else { |
692 | 0 | if (nmatch == sp->len) { |
693 | | /* this case should not happen */ |
694 | 0 | goto eat; |
695 | 0 | } |
696 | 0 | } |
697 | 0 | } |
698 | | |
699 | 0 | break; |
700 | 0 | } |
701 | | |
702 | 0 | eat: |
703 | | /* no letter to eat */ |
704 | 0 | if (n < 1) { |
705 | 0 | if (result) |
706 | 0 | *result = string; |
707 | 0 | return (_ISO2022INVALID); |
708 | 0 | } |
709 | | |
710 | | /* normal chars. always eat C0/C1 as is. */ |
711 | 0 | if (iscntl(*string & 0xff)) |
712 | 0 | cur = -1; |
713 | 0 | else if (*string & 0x80) |
714 | 0 | cur = (psenc->singlegr == -1) ? psenc->gr : psenc->singlegr; |
715 | 0 | else |
716 | 0 | cur = (psenc->singlegl == -1) ? psenc->gl : psenc->singlegl; |
717 | |
|
718 | 0 | if (cur == -1) { |
719 | 0 | asis: |
720 | 0 | wchar = *string++ & 0xff; |
721 | 0 | if (result) |
722 | 0 | *result = string; |
723 | | /* reset single shift state */ |
724 | 0 | psenc->singlegr = psenc->singlegl = -1; |
725 | 0 | return (wchar); |
726 | 0 | } |
727 | | |
728 | | /* length error check */ |
729 | 0 | switch (psenc->g[cur].type) { |
730 | 0 | case CS94MULTI: |
731 | 0 | case CS96MULTI: |
732 | 0 | if (!isthree(psenc->g[cur].final)) { |
733 | 0 | if (2 <= n && |
734 | 0 | (string[0] & 0x80) == (string[1] & 0x80)) |
735 | 0 | break; |
736 | 0 | } else { |
737 | 0 | if (3 <= n && |
738 | 0 | (string[0] & 0x80) == (string[1] & 0x80) && |
739 | 0 | (string[0] & 0x80) == (string[2] & 0x80)) |
740 | 0 | break; |
741 | 0 | } |
742 | | |
743 | | /* we still need to wait for more characters to come */ |
744 | 0 | if (result) |
745 | 0 | *result = string; |
746 | 0 | return (_ISO2022INVALID); |
747 | | |
748 | 0 | case CS94: |
749 | 0 | case CS96: |
750 | 0 | if (1 <= n) |
751 | 0 | break; |
752 | | |
753 | | /* we still need to wait for more characters to come */ |
754 | 0 | if (result) |
755 | 0 | *result = string; |
756 | 0 | return (_ISO2022INVALID); |
757 | 0 | } |
758 | | |
759 | | /* range check */ |
760 | 0 | switch (psenc->g[cur].type) { |
761 | 0 | case CS94: |
762 | 0 | if (!(is94(string[0] & 0x7f))) |
763 | 0 | goto asis; |
764 | 0 | break; |
765 | 0 | case CS96: |
766 | 0 | if (!(is96(string[0] & 0x7f))) |
767 | 0 | goto asis; |
768 | 0 | break; |
769 | 0 | case CS94MULTI: |
770 | 0 | if (!(is94(string[0] & 0x7f) && is94(string[1] & 0x7f))) |
771 | 0 | goto asis; |
772 | 0 | break; |
773 | 0 | case CS96MULTI: |
774 | 0 | if (!(is96(string[0] & 0x7f) && is96(string[1] & 0x7f))) |
775 | 0 | goto asis; |
776 | 0 | break; |
777 | 0 | } |
778 | | |
779 | | /* extract the character. */ |
780 | 0 | switch (psenc->g[cur].type) { |
781 | 0 | case CS94: |
782 | | /* special case for ASCII. */ |
783 | 0 | if (psenc->g[cur].final == 'B' && !psenc->g[cur].interm) { |
784 | 0 | wchar = *string++; |
785 | 0 | wchar &= 0x7f; |
786 | 0 | break; |
787 | 0 | } |
788 | 0 | wchar = psenc->g[cur].final; |
789 | 0 | wchar = (wchar << 8); |
790 | 0 | wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0); |
791 | 0 | wchar = (wchar << 8); |
792 | 0 | wchar = (wchar << 8) | (*string++ & 0x7f); |
793 | 0 | break; |
794 | 0 | case CS96: |
795 | | /* special case for ISO-8859-1. */ |
796 | 0 | if (psenc->g[cur].final == 'A' && !psenc->g[cur].interm) { |
797 | 0 | wchar = *string++; |
798 | 0 | wchar &= 0x7f; |
799 | 0 | wchar |= 0x80; |
800 | 0 | break; |
801 | 0 | } |
802 | 0 | wchar = psenc->g[cur].final; |
803 | 0 | wchar = (wchar << 8); |
804 | 0 | wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0); |
805 | 0 | wchar = (wchar << 8); |
806 | 0 | wchar = (wchar << 8) | (*string++ & 0x7f); |
807 | 0 | wchar |= 0x80; |
808 | 0 | break; |
809 | 0 | case CS94MULTI: |
810 | 0 | case CS96MULTI: |
811 | 0 | wchar = psenc->g[cur].final; |
812 | 0 | wchar = (wchar << 8); |
813 | 0 | if (isthree(psenc->g[cur].final)) |
814 | 0 | wchar |= (*string++ & 0x7f); |
815 | 0 | wchar = (wchar << 8) | (*string++ & 0x7f); |
816 | 0 | wchar = (wchar << 8) | (*string++ & 0x7f); |
817 | 0 | if (psenc->g[cur].type == CS96MULTI) |
818 | 0 | wchar |= 0x80; |
819 | 0 | break; |
820 | 0 | } |
821 | | |
822 | 0 | if (result) |
823 | 0 | *result = string; |
824 | | /* reset single shift state */ |
825 | 0 | psenc->singlegr = psenc->singlegl = -1; |
826 | 0 | return (wchar); |
827 | 0 | } |
828 | | |
829 | | |
830 | | |
831 | | static int |
832 | | _citrus_ISO2022_mbrtowc_priv(_ISO2022EncodingInfo * ei, |
833 | | _citrus_wc_t * pwc, char ** s, |
834 | | size_t n, _ISO2022State * psenc, size_t * nresult) |
835 | 0 | { |
836 | 0 | char *p, *result, *s0; |
837 | 0 | _citrus_wc_t wchar; |
838 | 0 | int chlenbak; |
839 | 0 | size_t c; |
840 | |
|
841 | 0 | if (*s == NULL) { |
842 | 0 | _citrus_ISO2022_init_state(ei, psenc); |
843 | 0 | *nresult = _ENCODING_IS_STATE_DEPENDENT; |
844 | 0 | return (0); |
845 | 0 | } |
846 | 0 | s0 = *s; |
847 | 0 | c = 0; |
848 | 0 | chlenbak = (int) psenc->chlen; |
849 | | |
850 | | /* |
851 | | * if we have something in buffer, use that. |
852 | | * otherwise, skip here |
853 | | */ |
854 | 0 | if (psenc->chlen > sizeof(psenc->ch)) { |
855 | | /* illgeal state */ |
856 | 0 | _citrus_ISO2022_init_state(ei, psenc); |
857 | 0 | goto encoding_error; |
858 | 0 | } |
859 | 0 | if (psenc->chlen == 0) |
860 | 0 | goto emptybuf; |
861 | | |
862 | | /* buffer is not empty */ |
863 | 0 | p = psenc->ch; |
864 | 0 | while (psenc->chlen < sizeof(psenc->ch)) { |
865 | 0 | if (n > 0) { |
866 | 0 | psenc->ch[psenc->chlen++] = *s0++; |
867 | 0 | n--; |
868 | 0 | } |
869 | |
|
870 | 0 | wchar = _ISO2022_sgetwchar(ei, p, psenc->chlen - (p-psenc->ch), |
871 | 0 | &result, psenc); |
872 | 0 | c += result - p; |
873 | 0 | if (wchar != _ISO2022INVALID) { |
874 | 0 | if (psenc->chlen > (size_t)c) |
875 | 0 | memmove(psenc->ch, result, psenc->chlen - c); |
876 | 0 | if (psenc->chlen < (size_t)c) |
877 | 0 | psenc->chlen = 0; |
878 | 0 | else |
879 | 0 | psenc->chlen -= c; |
880 | 0 | goto output; |
881 | 0 | } |
882 | | |
883 | 0 | if (n == 0) { |
884 | 0 | if ((size_t)(result - p) == psenc->chlen) |
885 | | /* complete shift sequence. */ |
886 | 0 | psenc->chlen = 0; |
887 | 0 | goto restart; |
888 | 0 | } |
889 | | |
890 | 0 | p = result; |
891 | 0 | } |
892 | | |
893 | | /* escape sequence too long? */ |
894 | 0 | goto encoding_error; |
895 | | |
896 | 0 | emptybuf: |
897 | 0 | wchar = _ISO2022_sgetwchar(ei, s0, n, &result, psenc); |
898 | 0 | if (wchar != _ISO2022INVALID) { |
899 | 0 | c += result - s0; |
900 | 0 | psenc->chlen = 0; |
901 | 0 | s0 = result; |
902 | 0 | goto output; |
903 | 0 | } |
904 | 0 | if (result > s0) { |
905 | 0 | c += (result - s0); |
906 | 0 | n -= (result - s0); |
907 | 0 | s0 = result; |
908 | 0 | if (n > 0) |
909 | 0 | goto emptybuf; |
910 | | /* complete shift sequence. */ |
911 | 0 | goto restart; |
912 | 0 | } |
913 | 0 | n += c; |
914 | 0 | if (n < sizeof(psenc->ch)) { |
915 | 0 | memcpy(psenc->ch, s0 - c, n); |
916 | 0 | psenc->chlen = n; |
917 | 0 | s0 = result; |
918 | 0 | goto restart; |
919 | 0 | } |
920 | | |
921 | | /* escape sequence too long? */ |
922 | | |
923 | 0 | encoding_error: |
924 | 0 | psenc->chlen = 0; |
925 | 0 | *nresult = (size_t)-1; |
926 | 0 | return (EILSEQ); |
927 | | |
928 | 0 | output: |
929 | 0 | *s = s0; |
930 | 0 | if (pwc) |
931 | 0 | *pwc = wchar; |
932 | 0 | *nresult = wchar ? c - chlenbak : 0; |
933 | 0 | return (0); |
934 | | |
935 | 0 | restart: |
936 | 0 | *s = s0; |
937 | 0 | *nresult = (size_t)-2; |
938 | |
|
939 | 0 | return (0); |
940 | 0 | } |
941 | | |
942 | | static int |
943 | | recommendation(_ISO2022EncodingInfo * ei, |
944 | | _ISO2022Charset * cs) |
945 | 0 | { |
946 | 0 | _ISO2022Charset *recommend; |
947 | 0 | size_t j; |
948 | 0 | int i; |
949 | | |
950 | | /* first, try a exact match. */ |
951 | 0 | for (i = 0; i < 4; i++) { |
952 | 0 | recommend = ei->recommend[i]; |
953 | 0 | for (j = 0; j < ei->recommendsize[i]; j++) { |
954 | 0 | if (cs->type != recommend[j].type) |
955 | 0 | continue; |
956 | 0 | if (cs->final != recommend[j].final) |
957 | 0 | continue; |
958 | 0 | if (cs->interm != recommend[j].interm) |
959 | 0 | continue; |
960 | | |
961 | 0 | return (i); |
962 | 0 | } |
963 | 0 | } |
964 | | |
965 | | /* then, try a wildcard match over final char. */ |
966 | 0 | for (i = 0; i < 4; i++) { |
967 | 0 | recommend = ei->recommend[i]; |
968 | 0 | for (j = 0; j < ei->recommendsize[i]; j++) { |
969 | 0 | if (cs->type != recommend[j].type) |
970 | 0 | continue; |
971 | 0 | if (cs->final && (cs->final != recommend[j].final)) |
972 | 0 | continue; |
973 | 0 | if (cs->interm && (cs->interm != recommend[j].interm)) |
974 | 0 | continue; |
975 | | |
976 | 0 | return (i); |
977 | 0 | } |
978 | 0 | } |
979 | | |
980 | | /* there's no recommendation. make a guess. */ |
981 | 0 | if (ei->maxcharset == 0) { |
982 | 0 | return (0); |
983 | 0 | } else { |
984 | 0 | switch (cs->type) { |
985 | 0 | case CS94: |
986 | 0 | case CS94MULTI: |
987 | 0 | return (0); |
988 | 0 | case CS96: |
989 | 0 | case CS96MULTI: |
990 | 0 | return (1); |
991 | 0 | } |
992 | 0 | } |
993 | 0 | return (0); |
994 | 0 | } |
995 | | |
996 | | static int |
997 | | _ISO2022_sputwchar(_ISO2022EncodingInfo * ei, _citrus_wc_t wc, |
998 | | char * string, size_t n, char ** result, |
999 | | _ISO2022State * psenc, size_t * nresult) |
1000 | 0 | { |
1001 | 0 | _ISO2022Charset cs; |
1002 | 0 | char *p; |
1003 | 0 | char tmp[MB_LEN_MAX]; |
1004 | 0 | size_t len; |
1005 | 0 | int bit8, i = 0, target; |
1006 | 0 | unsigned char mask; |
1007 | |
|
1008 | 0 | if (isc0(wc & 0xff)) { |
1009 | | /* go back to INIT0 or ASCII on control chars */ |
1010 | 0 | cs = ei->initg[0].final ? ei->initg[0] : ascii; |
1011 | 0 | } else if (isc1(wc & 0xff)) { |
1012 | | /* go back to INIT1 or ISO-8859-1 on control chars */ |
1013 | 0 | cs = ei->initg[1].final ? ei->initg[1] : iso88591; |
1014 | 0 | } else if (!(wc & ~0xff)) { |
1015 | 0 | if (wc & 0x80) { |
1016 | | /* special treatment for ISO-8859-1 */ |
1017 | 0 | cs = iso88591; |
1018 | 0 | } else { |
1019 | | /* special treatment for ASCII */ |
1020 | 0 | cs = ascii; |
1021 | 0 | } |
1022 | 0 | } else { |
1023 | 0 | cs.final = (wc >> 24) & 0x7f; |
1024 | 0 | if ((wc >> 16) & 0x80) |
1025 | 0 | cs.interm = (wc >> 16) & 0x7f; |
1026 | 0 | else |
1027 | 0 | cs.interm = '\0'; |
1028 | 0 | if (wc & 0x80) |
1029 | 0 | cs.type = (wc & 0x00007f00) ? CS96MULTI : CS96; |
1030 | 0 | else |
1031 | 0 | cs.type = (wc & 0x00007f00) ? CS94MULTI : CS94; |
1032 | 0 | } |
1033 | 0 | target = recommendation(ei, &cs); |
1034 | 0 | p = tmp; |
1035 | 0 | bit8 = ei->flags & F_8BIT; |
1036 | | |
1037 | | /* designate the charset onto the target plane(G0/1/2/3). */ |
1038 | 0 | if (psenc->g[target].type == cs.type && |
1039 | 0 | psenc->g[target].final == cs.final && |
1040 | 0 | psenc->g[target].interm == cs.interm) |
1041 | 0 | goto planeok; |
1042 | | |
1043 | 0 | *p++ = '\033'; |
1044 | 0 | if (cs.type == CS94MULTI || cs.type == CS96MULTI) |
1045 | 0 | *p++ = '$'; |
1046 | 0 | if (target == 0 && cs.type == CS94MULTI && strchr("@AB", cs.final) && |
1047 | 0 | !cs.interm && !(ei->flags & F_NOOLD)) |
1048 | 0 | ; |
1049 | 0 | else if (cs.type == CS94 || cs.type == CS94MULTI) |
1050 | 0 | *p++ = "()*+"[target]; |
1051 | 0 | else |
1052 | 0 | *p++ = ",-./"[target]; |
1053 | 0 | if (cs.interm) |
1054 | 0 | *p++ = cs.interm; |
1055 | 0 | *p++ = cs.final; |
1056 | |
|
1057 | 0 | psenc->g[target].type = cs.type; |
1058 | 0 | psenc->g[target].final = cs.final; |
1059 | 0 | psenc->g[target].interm = cs.interm; |
1060 | |
|
1061 | 0 | planeok: |
1062 | | /* invoke the plane onto GL or GR. */ |
1063 | 0 | if (psenc->gl == target) |
1064 | 0 | goto sideok; |
1065 | 0 | if (bit8 && psenc->gr == target) |
1066 | 0 | goto sideok; |
1067 | | |
1068 | 0 | if (target == 0 && (ei->flags & F_LS0)) { |
1069 | 0 | *p++ = '\017'; |
1070 | 0 | psenc->gl = 0; |
1071 | 0 | } else if (target == 1 && (ei->flags & F_LS1)) { |
1072 | 0 | *p++ = '\016'; |
1073 | 0 | psenc->gl = 1; |
1074 | 0 | } else if (target == 2 && (ei->flags & F_LS2)) { |
1075 | 0 | *p++ = '\033'; |
1076 | 0 | *p++ = 'n'; |
1077 | 0 | psenc->gl = 2; |
1078 | 0 | } else if (target == 3 && (ei->flags & F_LS3)) { |
1079 | 0 | *p++ = '\033'; |
1080 | 0 | *p++ = 'o'; |
1081 | 0 | psenc->gl = 3; |
1082 | 0 | } else if (bit8 && target == 1 && (ei->flags & F_LS1R)) { |
1083 | 0 | *p++ = '\033'; |
1084 | 0 | *p++ = '~'; |
1085 | 0 | psenc->gr = 1; |
1086 | 0 | } else if (bit8 && target == 2 && (ei->flags & F_LS2R)) { |
1087 | 0 | *p++ = '\033'; |
1088 | | /*{*/ |
1089 | 0 | *p++ = '}'; |
1090 | 0 | psenc->gr = 2; |
1091 | 0 | } else if (bit8 && target == 3 && (ei->flags & F_LS3R)) { |
1092 | 0 | *p++ = '\033'; |
1093 | 0 | *p++ = '|'; |
1094 | 0 | psenc->gr = 3; |
1095 | 0 | } else if (target == 2 && (ei->flags & F_SS2)) { |
1096 | 0 | *p++ = '\033'; |
1097 | 0 | *p++ = 'N'; |
1098 | 0 | psenc->singlegl = 2; |
1099 | 0 | } else if (target == 3 && (ei->flags & F_SS3)) { |
1100 | 0 | *p++ = '\033'; |
1101 | 0 | *p++ = 'O'; |
1102 | 0 | psenc->singlegl = 3; |
1103 | 0 | } else if (bit8 && target == 2 && (ei->flags & F_SS2R)) { |
1104 | 0 | *p++ = '\216'; |
1105 | 0 | *p++ = 'N'; |
1106 | 0 | psenc->singlegl = psenc->singlegr = 2; |
1107 | 0 | } else if (bit8 && target == 3 && (ei->flags & F_SS3R)) { |
1108 | 0 | *p++ = '\217'; |
1109 | 0 | *p++ = 'O'; |
1110 | 0 | psenc->singlegl = psenc->singlegr = 3; |
1111 | 0 | } else |
1112 | 0 | goto ilseq; |
1113 | | |
1114 | 0 | sideok: |
1115 | 0 | if (psenc->singlegl == target) |
1116 | 0 | mask = 0x00; |
1117 | 0 | else if (psenc->singlegr == target) |
1118 | 0 | mask = 0x80; |
1119 | 0 | else if (psenc->gl == target) |
1120 | 0 | mask = 0x00; |
1121 | 0 | else if ((ei->flags & F_8BIT) && psenc->gr == target) |
1122 | 0 | mask = 0x80; |
1123 | 0 | else |
1124 | 0 | goto ilseq; |
1125 | | |
1126 | 0 | switch (cs.type) { |
1127 | 0 | case CS94: |
1128 | 0 | case CS96: |
1129 | 0 | i = 1; |
1130 | 0 | break; |
1131 | 0 | case CS94MULTI: |
1132 | 0 | case CS96MULTI: |
1133 | 0 | i = !iscntl(wc & 0xff) ? |
1134 | 0 | (isthree(cs.final) ? 3 : 2) : 1; |
1135 | 0 | break; |
1136 | 0 | } |
1137 | 0 | while (i-- > 0) |
1138 | 0 | *p++ = ((wc >> (i << 3)) & 0x7f) | mask; |
1139 | | |
1140 | | /* reset single shift state */ |
1141 | 0 | psenc->singlegl = psenc->singlegr = -1; |
1142 | |
|
1143 | 0 | len = (size_t)(p - tmp); |
1144 | 0 | if (n < len) { |
1145 | 0 | if (result) |
1146 | 0 | *result = (char *)0; |
1147 | 0 | *nresult = (size_t)-1; |
1148 | 0 | return (E2BIG); |
1149 | 0 | } |
1150 | 0 | if (result) |
1151 | 0 | *result = string + len; |
1152 | 0 | memcpy(string, tmp, len); |
1153 | 0 | *nresult = len; |
1154 | |
|
1155 | 0 | return (0); |
1156 | | |
1157 | 0 | ilseq: |
1158 | 0 | *nresult = (size_t)-1; |
1159 | 0 | return (EILSEQ); |
1160 | 0 | } |
1161 | | |
1162 | | static int |
1163 | | _citrus_ISO2022_put_state_reset(_ISO2022EncodingInfo * ei, |
1164 | | char * s, size_t n, _ISO2022State * psenc, |
1165 | | size_t * nresult) |
1166 | 0 | { |
1167 | 0 | char *result; |
1168 | 0 | char buf[MB_LEN_MAX]; |
1169 | 0 | size_t len; |
1170 | 0 | int ret; |
1171 | | |
1172 | | /* XXX state will be modified after this operation... */ |
1173 | 0 | ret = _ISO2022_sputwchar(ei, L'\0', buf, sizeof(buf), &result, psenc, |
1174 | 0 | &len); |
1175 | 0 | if (ret) { |
1176 | 0 | *nresult = len; |
1177 | 0 | return (ret); |
1178 | 0 | } |
1179 | | |
1180 | 0 | if (sizeof(buf) < len || n < len-1) { |
1181 | | /* XXX should recover state? */ |
1182 | 0 | *nresult = (size_t)-1; |
1183 | 0 | return (E2BIG); |
1184 | 0 | } |
1185 | | |
1186 | 0 | memcpy(s, buf, len - 1); |
1187 | 0 | *nresult = len - 1; |
1188 | 0 | return (0); |
1189 | 0 | } |
1190 | | |
1191 | | static int |
1192 | | _citrus_ISO2022_wcrtomb_priv(_ISO2022EncodingInfo * ei, |
1193 | | char * s, size_t n, _citrus_wc_t wc, |
1194 | | _ISO2022State * psenc, size_t * nresult) |
1195 | 0 | { |
1196 | 0 | char *result; |
1197 | 0 | char buf[MB_LEN_MAX]; |
1198 | 0 | size_t len; |
1199 | 0 | int ret; |
1200 | | |
1201 | | /* XXX state will be modified after this operation... */ |
1202 | 0 | ret = _ISO2022_sputwchar(ei, wc, buf, sizeof(buf), &result, psenc, |
1203 | 0 | &len); |
1204 | 0 | if (ret) { |
1205 | 0 | *nresult = len; |
1206 | 0 | return (ret); |
1207 | 0 | } |
1208 | | |
1209 | 0 | if (sizeof(buf) < len || n < len) { |
1210 | | /* XXX should recover state? */ |
1211 | 0 | *nresult = (size_t)-1; |
1212 | 0 | return (E2BIG); |
1213 | 0 | } |
1214 | | |
1215 | 0 | memcpy(s, buf, len); |
1216 | 0 | *nresult = len; |
1217 | 0 | return (0); |
1218 | 0 | } |
1219 | | |
1220 | | static __inline int |
1221 | | /*ARGSUSED*/ |
1222 | | _citrus_ISO2022_stdenc_wctocs(_ISO2022EncodingInfo * ei , |
1223 | | _citrus_csid_t * csid, _citrus_index_t * idx, _citrus_wc_t wc) |
1224 | 0 | { |
1225 | 0 | _citrus_wc_t m, nm; |
1226 | 0 | (void) ei; |
1227 | |
|
1228 | 0 | m = wc & 0x7FFF8080; |
1229 | 0 | nm = wc & 0x007F7F7F; |
1230 | 0 | if (m & 0x00800000) |
1231 | 0 | nm &= 0x00007F7F; |
1232 | 0 | else |
1233 | 0 | m &= 0x7F008080; |
1234 | 0 | if (nm & 0x007F0000) { |
1235 | | /* ^3 mark */ |
1236 | 0 | m |= 0x007F0000; |
1237 | 0 | } else if (nm & 0x00007F00) { |
1238 | | /* ^2 mark */ |
1239 | 0 | m |= 0x00007F00; |
1240 | 0 | } |
1241 | 0 | *csid = (_citrus_csid_t)m; |
1242 | 0 | *idx = (_citrus_index_t)nm; |
1243 | |
|
1244 | 0 | return (0); |
1245 | 0 | } |
1246 | | |
1247 | | static __inline int |
1248 | | /*ARGSUSED*/ |
1249 | | _citrus_ISO2022_stdenc_cstowc(_ISO2022EncodingInfo * ei , |
1250 | | _citrus_wc_t * wc, _citrus_csid_t csid, _citrus_index_t idx) |
1251 | 0 | { |
1252 | 0 | (void) ei; |
1253 | |
|
1254 | 0 | *wc = (_citrus_wc_t)(csid & 0x7F808080) | (_citrus_wc_t)idx; |
1255 | |
|
1256 | 0 | return (0); |
1257 | 0 | } |
1258 | | |
1259 | | static __inline int |
1260 | | /*ARGSUSED*/ |
1261 | | _citrus_ISO2022_stdenc_get_state_desc_generic(_ISO2022EncodingInfo * ei , |
1262 | | _ISO2022State * psenc, int * rstate) |
1263 | 0 | { |
1264 | 0 | (void) ei; |
1265 | |
|
1266 | 0 | if (psenc->chlen == 0) { |
1267 | | /* XXX: it should distinguish initial and stable. */ |
1268 | 0 | *rstate = _CITRUS_STDENC_SDGEN_STABLE; |
1269 | 0 | } else |
1270 | 0 | *rstate = (psenc->ch[0] == '\033') ? |
1271 | 0 | _CITRUS_STDENC_SDGEN_INCOMPLETE_SHIFT : |
1272 | 0 | _CITRUS_STDENC_SDGEN_INCOMPLETE_CHAR; |
1273 | 0 | return (0); |
1274 | 0 | } |
1275 | | |
1276 | | /* ---------------------------------------------------------------------- |
1277 | | * public interface for stdenc |
1278 | | */ |
1279 | | |
1280 | | _CITRUS_STDENC_DECLS(ISO2022); |
1281 | | _CITRUS_STDENC_DEF_OPS(ISO2022); |
1282 | | |
1283 | | #include "citrus_stdenc_template.h" |