File Coverage

sjis_jsky2.c
Criterion Covered Total %
statement 116 242 47.9
branch 114 518 22.0
condition n/a
subroutine n/a
pod n/a
total 230 760 30.2


line stmt bran cond sub pod time code
1              
2             /* $Id: sjis_jsky2.c 4692 2007-09-07 10:10:20Z hio $ */
3              
4             #include "Japanese.h"
5             #include
6              
7             #ifndef __cplusplus
8             #undef bool
9             #undef true
10             #undef false
11             typedef enum bool { false, true, } bool;
12             #endif
13              
14             #define DISP_U2S 0
15             #define DISP_S2U 0
16              
17             #if DISP_U2S
18             #define ECHO_U2S(arg) fprintf arg
19             #define ON_U2S(cmd) cmd
20             #else
21             #define ECHO_U2S(arg)
22             #define ON_U2S(cmd)
23             #endif
24             #if DISP_S2U
25             #define ECHO_S2U(arg) fprintf arg
26             #define ON_S2U(cmd) cmd
27             #else
28             #define ECHO_S2U(arg)
29             #define ON_S2U(cmd)
30             #endif
31              
32             /* ----------------------------------------------------------------------------
33             * SV* sv_utf8 = xs_sjis_jsky2_utf8(SV* sv_sjis)
34             * convert sjis(jsky2) into utf8.
35             * ------------------------------------------------------------------------- */
36             EXTERN_C
37             SV*
38 40           xs_sjis_jsky2_utf8(SV* sv_str)
39             {
40             UJ_UINT8* src;
41             STRLEN len;
42            
43             SV_Buf result;
44             const UJ_UINT8* src_end;
45            
46 40 50         if( sv_str==&PL_sv_undef )
47             {
48 0           return newSVsv(&PL_sv_undef);
49             }
50 40 50         if( SvGMAGICAL(sv_str) )
51             {
52 0           mg_get(sv_str);
53             }
54 40 50         if( !SvOK(sv_str) )
55             {
56 0           return newSVsv(&PL_sv_undef);
57             }
58            
59 40           src = (UJ_UINT8*)SvPV(sv_str, len);
60             #if DISP_S2U
61             fprintf(stderr,"Unicode::Japanese::(xs)sjis_utf8_jsky2, len=%d\n",len);
62             bin_dump("in ",src,len);
63             #endif
64 40 50         SV_Buf_init(&result,len*3/2+4);
    50          
65 40           src_end = src+len;
66              
67 80 100         while( src
68             {
69             const UJ_UINT8* ptr;
70 40 100         if( src[0]<0x80 )
71 38           { /* ASCII */
72             UJ_UINT8* begin;
73             int j1;
74             const UJ_UINT32* table;
75             ECHO_U2S((stderr,"ascii: %02x\n",src[0]));
76            
77 38 50         if( src[0]!='\x1b' || src+2>=src_end || src[1]!='$' )
    50          
    50          
78             { /* not emoji. */
79 0 0         SV_Buf_append_ch(&result,*src);
    0          
    0          
80 0           ++src;
81 0           continue;
82             }
83             /*fprint(stderr,"detect j-sky emoji-start escape\n"); */
84             /* E_JSKY_1 */
85 38 100         if( src[2]=='E' || src[2]=='F' || src[2]=='G' )
    100          
    100          
86             {
87 25           j1 = (src[2]-'E')<<8;
88 25           table = g_ej2u1_table;
89             ECHO_U2S((stderr,"src[2]: %02x '%c' j1:%04x\n",src[2],src[2],j1));
90 13 100         }else if( src[2]=='O' || src[2]=='P' || src[2]=='Q' )
    100          
    50          
91             {
92 13           j1 = (src[2]-'O')<<8;
93 13           table = g_ej2u2_table;
94             ECHO_U2S((stderr,"src[2]: %02x '%c' j1:%04x\n",src[2],src[2],j1));
95             }else
96             {
97             /*fprintf(stderr,"first char is invalid"); */
98 0 0         SV_Buf_append_ch(&result,*src);
    0          
    0          
99 0           ++src;
100 0           continue;
101             }
102            
103 38           begin = src;
104 38           src += 3;
105             /* E_JSKY_2 */
106 77 100         while( src
107             {
108 73 100         if( '!'<=src[0] && src[0]<='z' )
    50          
109             {
110 39           ++src;
111 39           continue;
112             }
113 34           break;
114             }
115 38 100         if( src
    50          
116             {
117             /* accept, normally. */
118 4 50         }else if( src==src_end )
119             {
120             /* accept, without terminator. */
121             }else
122             {
123             /* invalid, rollback. */
124 0 0         SV_Buf_append_ch(&result, '\x1b');
    0          
    0          
125 0           src = begin+1;
126 0           continue;
127             }
128 77 100         for( ptr = begin+3; ptr
129             {
130             /*fprintf(stderr," <%c%c:%04x>\n",begin[2],*ptr,j1+*ptr); */
131             /*fprintf(stderr," => %04x\n",g_ej2u2_table[j1+*ptr]); */
132 39           const UJ_UINT8* str = (UJ_UINT8*)&table[j1+*ptr];
133             /*fprintf(stderr," len: %d\n",str[3]?4:strlen((char*)str)); */
134 39 50         SV_Buf_append_mem(&result,str,str[3]?4:strlen((char*)str));
    50          
    0          
    0          
    0          
    50          
    50          
135             }
136             /*fprintf(stderr,"j-sky string done.\n"); */
137            
138             /* '\x0f' をスキップ. */
139             /* src==src_end の時はバッファを超えるけど, */
140             /* その時はこれ以上はアクセスしないので気にしない. */
141 38           ++src;
142 38           continue;
143 2 50         }else if( 0xa1<=src[0] && src[0]<=0xdf )
    0          
144             { /* half-width katakana (ja:半角カナ) */
145             ECHO_U2S((stderr,"kana: %02x\n",src[0]));
146 0           ptr = (UJ_UINT8*)&g_s2u_table[(src[0]-0xa1)*3];
147 0           ++src;
148 2 50         }else if( src+1
    50          
    50          
149 2           { /* a double-byte letter (ja:2バイト文字) */
150 2           const UJ_UINT16 sjis = (src[0]<<8)+src[1]; /* ntohs */
151             ECHO_U2S((stderr,"sjis.dbcs#1: %04x\n",sjis));
152 2           ptr = (UJ_UINT8*)&g_s2u_table[(sjis - 0x8100 + 0x3f)*3];
153 2           src += 2;
154 0 0         }else if( src+1
    0          
    0          
155 0           { /* a double-byte letter (ja:2バイト文字) */
156 0           const UJ_UINT16 sjis = (src[0]<<8)+src[1]; /* ntohs */
157             ECHO_U2S((stderr,"sjis.dbcs#2: %04x\n",sjis));
158 0           ptr = (UJ_UINT8*)&g_s2u_table[(sjis- 0xe000 + 0x1f3f)*3];
159 0           src += 2;
160             }else
161             { /* unknown */
162             /*fprintf(stderr,"unknown: %02x\n",src[0]); */
163 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
164 0           ++src;
165 0           continue;
166             }
167              
168             ECHO_U2S((stderr,"offset: 0x%04x\n",ptr-g_s2u_table));
169             ECHO_U2S((stderr,"utf8-char : %02x %02x %02x\n",ptr[0],ptr[1],ptr[2]));
170 2 50         if( ptr[2] )
171             {
172             /*fprintf(stderr,"utf8-len: [%d]\n",3); */
173 2 50         SV_Buf_append_mem(&result, ptr, 3);
    0          
    0          
174 0 0         }else if( ptr[1] )
175             {
176             /*fprintf(stderr,"utf8-len: [%d]\n",2); */
177 0 0         SV_Buf_append_mem(&result, ptr, 2);
    0          
    0          
178 0 0         }else if( ptr[0] )
179             {
180             /*fprintf(stderr,"utf8-len: [%d]\n",1); */
181 0 0         SV_Buf_append_ch(&result,*ptr);
    0          
    0          
182             }else
183             {
184 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
185             }
186             }
187             ON_S2U( bin_dump("out",SV_Buf_getBegin(&result),SV_Buf_getLength(&result)) );
188 40           SV_Buf_setLength(&result);
189              
190 40           return SV_Buf_getSv(&result);
191             }
192              
193             /* ---------------------------------------------------------------------------
194             * utf8 ==> jsky2
195             * ------------------------------------------------------------------------- */
196             EXTERN_C
197             SV*
198 37           xs_utf8_sjis_jsky2(SV* sv_str)
199             {
200             UJ_UINT8* src;
201             STRLEN len;
202             SV_Buf result;
203             const UJ_UINT8* src_end;
204              
205 37 50         if( sv_str==&PL_sv_undef )
206             {
207 0           return newSVsv(&PL_sv_undef);
208             }
209 37 50         if( SvGMAGICAL(sv_str) )
210             {
211 0           mg_get(sv_str);
212             }
213 37 50         if( !SvOK(sv_str) )
214             {
215 0           return newSVsv(&PL_sv_undef);
216             }
217 37           src = (UJ_UINT8*)SvPV(sv_str, len);
218              
219             ECHO_U2S((stderr,"Unicode::Japanese::(xs)utf8_sjis_jsky2\n"));
220             ON_U2S( bin_dump("in ",src,len) );
221              
222 37 50         SV_Buf_init(&result,len+4);
    50          
223 37           src_end = src+len;
224              
225 76 100         while( src
226             {
227             UJ_UINT32 ucs;
228             const UJ_UINT8* sjis_ptr;
229            
230 39 50         if( *src<=0x7f )
231 0           {
232             /* ascii chars sequence (ja:ASCIIはまとめて追加〜) */
233 0           int len = 1;
234 0 0         while( src+len
    0          
235             {
236 0           ++len;
237             }
238 0 0         SV_Buf_append_mem(&result,src,len);
    0          
    0          
239 0           src+=len;
240 0           continue;
241             }
242            
243             /* non-ascii */
244 39 50         if( 0xe0<=*src && *src<=0xef )
    100          
245 3           { /* 3byte range. mostly enter here. */
246 3           const int utf8_len = 3;
247 3           const UJ_UINT32 ucs_min = 0x800;
248 3           const UJ_UINT32 ucs_max = 0xffff;
249             ECHO_U2S((stderr,"utf8-len: [%d]\n",utf8_len));
250             /* check length */
251 3 50         if( src+utf8_len<=src_end )
252             { /* noop */
253             }else
254             { /* no enough sequence */
255 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
256 0           ++src;
257 0           continue;
258             }
259             /* check follow sequences */
260 3 50         if( 0x80<=src[1] && src[1]<=0xbf && 0x80<=src[2] && src[2]<=0xbf )
    50          
    50          
    50          
261             { /* noop */
262             }else
263             {
264 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
265 0           ++src;
266 0           continue;
267             }
268            
269             /* compute code point */
270 3           ucs = ((src[0] & 0x0F)<<12)|((src[1] & 0x3F)<<6)|(src[2] & 0x3F);
271 3           src += utf8_len;
272 3 50         if( ucs_min<=ucs && ucs<=ucs_max )
    50          
273             { /* noop */
274             }else
275             { /* illegal sequence */
276 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
277 0           continue;
278             }
279             /* ok. */
280 36 50         }else if( 0xf0<=*src && *src<=0xf7 )
    50          
281 0           {
282 36           const int utf8_len = 4;
283 36           const UJ_UINT32 ucs_min = 0x010000;
284 36           const UJ_UINT32 ucs_max = 0x10ffff;
285             ECHO_U2S((stderr,"utf8-len: [%d]\n",utf8_len));
286             /* check length */
287 36 50         if( src+utf8_len<=src_end )
288             { /* noop */
289             }else
290             { /* no enough sequence */
291 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
292 0           ++src;
293 0           continue;
294             }
295             /* check follow sequences */
296 36 50         if( 0x80<=src[1] && src[1]<=0xbf && 0x80<=src[2] && src[2]<=0xbf
    50          
    50          
    50          
297 36 50         && 0x80<=src[3] && src[3]<=0xbf )
    50          
298             { /* noop */
299             }else
300             {
301 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
302 0           ++src;
303 0           continue;
304             }
305            
306             /* compute code point */
307 36           ucs = ((src[0] & 0x07)<<18)|((src[1] & 0x3F)<<12)|
308 36           ((src[2] & 0x3f) << 6)|(src[3] & 0x3F);
309 36           src += utf8_len;
310 36 50         if( ucs_min<=ucs && ucs<=ucs_max )
    50          
311             { /* noop */
312             }else
313             { /* illegal sequence */
314 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
315 0           continue;
316             }
317             /* private area: block emoji */
318 36 50         if( 0x0f0000<=ucs && ucs<=0x0fffff )
    50          
319 36           {
320             const UJ_UINT8* sjis;
321 36 50         if( ucs<0x0fe000 )
322             { /* unknown area. */
323 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
324 0           continue;
325             }
326             /* j-sky2 emoji */
327 36           sjis = &g_eu2j2_table[(ucs - 0x0fe000)*5];
328             /*fprintf(stderr," emoji: %02x %02x %02x %02x %02x\n", */
329             /* sjis[0],sjis[1],sjis[2],sjis[3],sjis[4]); */
330 36 100         if( sjis[4]!=0 )
331             { /* 5 bytes */
332 35 50         SV_Buf_append_ch5(&result,sjis);
    0          
    0          
333 1 50         }else if( sjis[3]!=0 )
334             { /* 4 bytes. */
335             assert("not reach here" && 0);
336 0 0         SV_Buf_append_mem(&result, sjis, 4);
    0          
    0          
337 1 50         }else if( sjis[2]!=0 )
338             { /* 3 bytes. */
339             assert("not reach here" && 0);
340 0 0         SV_Buf_append_mem(&result, sjis, 3);
    0          
    0          
341 1 50         }else if( sjis[1]!=0 )
342             { /* 2 bytes. */
343 1 50         SV_Buf_append_mem(&result, sjis, 2);
    0          
    0          
344 0 0         }else if( sjis[0]!=0 )
345             { /* 1 byte. */
346 0 0         SV_Buf_append_ch(&result,*sjis);
    0          
    0          
347             }else
348             { /* no mapping */
349 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
350             }
351 36           continue;
352             }
353            
354             /* > U+10FFFF not supported by UTF-8 (RFC 3629). */
355 0 0         if( ucs>0x10FFFF )
356             {
357 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
358 0           continue;
359             }
360 0 0         }else if( 0xc0<=*src && *src<=0xdf )
    0          
361 0           {
362 0           const int utf8_len = 2;
363 0           const UJ_UINT32 ucs_min = 0x80;
364 0           const UJ_UINT32 ucs_max = 0x7ff;
365             ECHO_U2S((stderr,"utf8-len: [%d]\n",utf8_len));
366             /* check length */
367 0 0         if( src+utf8_len<=src_end )
368             { /* noop */
369             }else
370             { /* no enough sequence */
371 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
372 0           ++src;
373 0           continue;
374             }
375             /* check follow sequences */
376 0 0         if( 0x80<=src[1] && src[1]<=0xbf )
    0          
377             { /* noop */
378             }else
379             {
380 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
381 0           ++src;
382 0           continue;
383             }
384            
385             /* compute code point */
386 0           ucs = ((src[0] & 0x1F)<<6)|(src[1] & 0x3F);
387 0           src += utf8_len;
388 0 0         if( ucs_min<=ucs && ucs<=ucs_max )
    0          
389             { /* noop */
390             }else
391             { /* illegal sequence */
392 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
393 0           continue;
394             }
395            
396             /* ok. */
397 0 0         }else if( 0xf8<=*src && *src<=0xfb )
    0          
398 0           {
399 0           const int utf8_len = 5;
400             ECHO_U2S((stderr,"utf8-len: [%d]\n",utf8_len));
401             /* check length */
402 0 0         if( src+utf8_len<=src_end )
403             { /* noop */
404             }else
405             { /* no enough sequence */
406 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
407 0           ++src;
408 0           continue;
409             }
410             /* check follow sequences */
411 0 0         if( 0x80<=src[1] && src[1]<=0xbf && 0x80<=src[2] && src[2]<=0xbf
    0          
    0          
    0          
412 0 0         && 0x80<=src[3] && src[3]<=0xbf && 0x80<=src[4] && src[4]<=0xbf )
    0          
    0          
    0          
413             { /* noop */
414             }else
415             {
416 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
417 0           ++src;
418 0           continue;
419             }
420            
421             /* compute code point */
422             /* > U+10FFFF not supported by UTF-8 (RFC 3629). */
423 0           src += utf8_len;
424 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
425 0           continue;
426 0 0         }else if( 0xfc<=*src && *src<=0xfd )
    0          
427 0           {
428 0           const int utf8_len = 6;
429             ECHO_U2S((stderr,"utf8-len: [%d]\n",utf8_len));
430             /* check length */
431 0 0         if( src+utf8_len<=src_end )
432             { /* noop */
433             }else
434             { /* no enough sequence */
435 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
436 0           ++src;
437 0           continue;
438             }
439             /* check follow sequences */
440 0 0         if( 0x80<=src[1] && src[1]<=0xbf && 0x80<=src[2] && src[2]<=0xbf
    0          
    0          
    0          
441 0 0         && 0x80<=src[3] && src[3]<=0xbf && 0x80<=src[4] && src[4]<=0xbf
    0          
    0          
    0          
442 0 0         && 0x80<=src[5] && src[5]<=0xbf )
    0          
443             { /* noop */
444             }else
445             {
446 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
447 0           ++src;
448 0           continue;
449             }
450            
451             /* compute code point */
452             /* > U+10FFFF not supported by UTF-8 (RFC 3629). */
453 0           src += utf8_len;
454 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
455 0           continue;
456             }else
457             {
458 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
459 0           ++src;
460 0           continue;
461             }
462            
463             /* ucs => sjis */
464             ECHO_U2S((stderr,"ucs [%04x]\n",ucs));
465 3 50         if( ucs<=0x9FFF )
466             {
467 3           sjis_ptr = g_u2s_table + ucs*2;
468 0 0         }else if( 0xF900<=ucs && ucs<=0xFFFF )
    0          
469             {
470 0           sjis_ptr = g_u2s_table + (ucs - 0xF900 + 0xA000)*2;
471 0 0         }else if( 0x0FE000<=ucs && ucs<=0x0FFFFF )
    0          
472             {
473 0           sjis_ptr = (UJ_UINT8*)"?"; /* exactly 2byte: "?\0" */
474             }else
475             {
476 0           sjis_ptr = (UJ_UINT8*)"\0"; /* exactly 2byte: "\0\0" */
477             }
478 3 100         if( sjis_ptr[0]!=0 || sjis_ptr[1]!=0 )
    50          
479             { /* mapping dest exists. */
480 2 50         if( sjis_ptr[1]!=0 )
481             {
482 2 50         SV_Buf_append_mem(&result, sjis_ptr, 2);
    0          
    0          
483             }else
484             {
485 0 0         SV_Buf_append_ch(&result,sjis_ptr[0]);
    0          
    0          
486             }
487 1 50         }else if( ucs<=0x7F )
488             {
489 0 0         SV_Buf_append_ch(&result,(UJ_UINT8)ucs);
    0          
    0          
490             }else
491             {
492 1 50         SV_Buf_append_ch(&result,'?');
    0          
    0          
493             }
494             } /* while */
495              
496             ON_U2S( bin_dump("out",SV_Buf_getBegin(&result),SV_Buf_getLength(&result)) );
497 37           SV_Buf_setLength(&result);
498              
499 37           sv_2mortal(SV_Buf_getSv(&result));
500             {
501             /* packing J-SKY emoji escapes */
502             SV_Buf pack;
503             UJ_UINT8* ptr;
504 37           UJ_UINT8 tmpl[5] = { '\x1b','$',0,0,'\x0f',};
505            
506 37 50         SV_Buf_init(&pack,SV_Buf_getLength(&result));
    50          
507 37           src = SV_Buf_getBegin(&result);
508 37           src_end = src + SV_Buf_getLength(&result);
509 37           ptr = src;
510 38 100         for( ; src+5*2-1
511             {
512             UJ_UINT8 ch1;
513             /* E_JSKY_START "\x1b\$", */
514 1 50         if( src[0]!='\x1b' ) continue;
515 1 50         if( src[1]!='$' ) continue;
516             /* E_JSKY1 '[EFG]', */
517             /*fprintf(stderr," found emoji-start\n"); */
518 1 50         if( src[2]!='E' && src[2]!='F' && src[2]!='G'
    50          
    0          
519 0 0         && src[2]!='O' && src[2]!='P' && src[2]!='Q' )
    0          
    0          
520             {
521             /*fprintf(stderr," invalid ch1 [%x:%02x]\n",src[2],src[2]); */
522 0           continue;
523             }
524 1           ch1 = src[2];
525             /* E_JSKY2 '[\!-\;\=-z\xbc]', */
526 1 50         if( src[3]<'!' || 'z'
    50          
527             {
528             /*fprintf(stderr," invalid ch2 [%02x]\n",src[3]); */
529 0           continue;
530             }
531             /* E_JSKY_END "\x0f", */
532 1 50         if( src[4]!='\x0f' ) continue;
533              
534             /*fprintf(stderr," found first emoji [%02x:%c]\n",ch1,ch1); */
535 1           src += 5;
536 1 50         SV_Buf_append_mem(&pack,ptr,(src-1)-ptr);
    0          
    0          
537 1           tmpl[2] = ch1;
538 2 100         for( ; src_end-src>=5; src+= 5 )
539             {
540 1           tmpl[3] = src[3];
541 1 50         if( memcmp(src,tmpl,5)!=0 ) break;
542             /*fprintf(stderr," packing...[%02x]\n",src[3]); */
543 1 50         SV_Buf_append_ch(&pack,src[3]);
    0          
    0          
544             }
545             /*fprintf(stderr," pack done.\n"); */
546 1 50         SV_Buf_append_ch(&pack,'\x0f');
    0          
    0          
547 1           ptr = src;
548             }
549             /*fprintf(stderr," pack complete.\n"); */
550             /*fprintf(stderr," append len %0d\n",src_end-ptr); */
551 37 100         if( ptr!=src_end )
552             {
553 36 50         SV_Buf_append_mem(&pack,ptr,src_end-ptr);
    50          
    100          
554             }
555              
556             ON_U2S( bin_dump("out",SV_Buf_getBegin(&pack),SV_Buf_getLength(&pack)) );
557 37           SV_Buf_setLength(&pack);
558              
559 37           return SV_Buf_getSv(&pack);
560             }
561             }