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