File Coverage

utf16.c
Criterion Covered Total %
statement 97 153 63.4
branch 88 312 28.2
condition n/a
subroutine n/a
pod n/a
total 185 465 39.7


line stmt bran cond sub pod time code
1             /* ----------------------------------------------------------------------------
2             * utf16_utf8.c
3             * ----------------------------------------------------------------------------
4             * Mastering programed by YAMASHINA Hio
5             * ----------------------------------------------------------------------------
6             * $Id: utf16.c 4654 2006-07-03 01:33:16Z hio $
7             * ------------------------------------------------------------------------- */
8              
9              
10             #include "Japanese.h"
11              
12             #define ENABLE_SURROGATE_PAIR 1
13              
14             /* ----------------------------------------------------------------------------
15             * convert utf-16 into utf-8
16             * ------------------------------------------------------------------------- */
17             EXTERN_C
18             SV*
19 5           xs_utf16_utf8(SV* sv_str)
20             {
21             UJ_UINT8* src;
22             STRLEN len;
23             SV_Buf result;
24             const UJ_UINT8* src_end;
25             union {
26             UJ_UINT32 u32_val;
27             UJ_UINT16 u16_val;
28             UJ_UINT8 u8_val[4];
29             } buf;
30              
31 5 50         if( sv_str==&PL_sv_undef )
32             {
33 0           return newSVpvn("",0);
34             }
35 5 50         if( SvGMAGICAL(sv_str) )
36             {
37 0           mg_get(sv_str);
38             }
39 5 50         if( !SvOK(sv_str) )
40             {
41 0           return newSVpvn("",0);
42             }
43            
44 5           src = (UJ_UINT8*)SvPV(sv_str, len);
45 5           src_end = src+(len&~1);
46             /*fprintf(stderr,"Unicode::Japanese::(xs)utf16_utf8\n",len);*/
47             /*bin_dump("in ",src,len);*/
48 5 50         SV_Buf_init(&result,len*3/2+4);
    50          
49              
50 5 50         if( len&1 )
51             {
52 0           Perl_croak(aTHX_ "Unicode::Japanese::utf16_utf8, invalid length (not 2*n)");
53             }
54              
55 10 100         for(; src
56             {
57 5           const UJ_UINT16 utf16 = (src[0]<<8)+src[1]; /* ntohs */
58 5 50         if( utf16<0x80 )
59             {
60 0 0         SV_Buf_append_ch(&result,(UJ_UINT8)utf16);
    0          
    0          
61 5 50         }else if( utf16<0x800 )
62             {
63 0           buf.u8_val[0] = 0xC0 | (utf16 >> 6);
64 0           buf.u8_val[1] = 0x80 | (utf16 & 0x3F);
65 0 0         SV_Buf_append_ch2(&result, buf.u16_val);
    0          
    0          
66 5 50         }else if( !(0xd800 <= utf16 && utf16 <= 0xdfff) )
    50          
67             { /* normal char (non surrogate pair) */
68 0           buf.u8_val[0] = 0xE0 | (utf16 >> 12);
69 0           buf.u8_val[1] = 0x80 | ((utf16 >> 6) & 0x3F);
70 0           buf.u8_val[2] = 0x80 | (utf16 & 0x3F);
71 0 0         SV_Buf_append_ch3(&result, buf.u32_val);
    0          
    0          
72             }else
73             { /* surrogate pair */
74 5 50         if( src+2
75             {
76 5           const UJ_UINT16 utf16a = (src[2]<<8)+src[3]; /* ntohs */
77 5 50         if( utf16<=0xdbff && 0xdc00 <= utf16a && utf16a <= 0xdfff )
    50          
    50          
78 5           {
79             #if ENABLE_SURROGATE_PAIR
80 5           const UJ_UINT32 ucs4 = ((utf16&0x03FF)<<10|(utf16a&0x03FF))+0x010000;
81 5           src += 2;
82 5 50         if( 0x010000<=ucs4 && ucs4<=0x10FFFF )
    50          
83             {
84 5           buf.u8_val[0] = 0xF0 | ((ucs4>>18) & 0x3F);
85 5           buf.u8_val[1] = 0x80 | ((ucs4>>12) & 0x3F);
86 5           buf.u8_val[2] = 0x80 | ((ucs4>>6) & 0x3F);
87 5           buf.u8_val[3] = 0x80 | (ucs4 & 0x3F);
88 5 50         SV_Buf_append_ch4(&result, buf.u32_val);
    0          
    0          
89             }else
90             {
91             /* utf8 not support >= U+10FFFF */
92             /* or illegal representation */
93 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
94             }
95             #else
96             {
97             /* surrogate pair disabled. */
98             SV_Buf_append_ch(&result,'?');
99             }
100             #endif
101             }else
102             {
103             /* invalid surrogate */
104 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
105             }
106             }else
107             {
108             /* no trail surrogate */
109 0 0         SV_Buf_append_ch(&result,'?');
    0          
    0          
110             }
111             }
112             }
113              
114             /*bin_dump("out",result.getBegin(),result.getLength()); */
115 5           SV_Buf_setLength(&result);
116              
117 5           return SV_Buf_getSv(&result);
118             }
119              
120             /* ----------------------------------------------------------------------------
121             * convert utf-8 into utf-16
122             * ------------------------------------------------------------------------- */
123             EXTERN_C
124             SV*
125 6           xs_utf8_utf16(SV* sv_str)
126             {
127             UJ_UINT8* src;
128             STRLEN len;
129             SV_Buf result;
130             const UJ_UINT8* src_end;
131              
132 6 50         if( sv_str==&PL_sv_undef )
133             {
134 0           return newSVpvn("",0);
135             }
136 6 50         if( SvGMAGICAL(sv_str) )
137             {
138 0           mg_get(sv_str);
139             }
140 6 50         if( !SvOK(sv_str) )
141             {
142 0           return newSVpvn("",0);
143             }
144            
145 6           src = (UJ_UINT8*)SvPV(sv_str, len);
146 6           src_end = src+len;
147             /*fprintf(stderr,"Unicode::Japanese::(xs)utf8_utf16\n",len); */
148             /*bin_dump("in ",src,len); */
149 6 50         SV_Buf_init(&result,len*2);
    50          
150            
151 12 100         while( src
152             {
153             UJ_UINT32 ucs;
154 6 100         if( *src<=0x7f )
155             {
156 1 50         SV_Buf_append_ch2(&result,htons(*src));
    50          
    50          
157 1           ++src;
158 1           continue;
159             }
160 5 50         if( 0xc0<=*src && *src<=0xdf )
    100          
161 0           { /* length [2] */
162 1           const int utf8_len = 2;
163 1           const UJ_UINT32 ucs_min = 0x80;
164 1           const UJ_UINT32 ucs_max = 0x7ff;
165 1 50         if( src+1>=src_end ||
166 1 50         src[1]<0x80 || 0xbf
    50          
167             {
168 0 0         SV_Buf_append_ch2(&result,htons(*src));
    0          
    0          
169 0           ++src;
170 0           continue;
171             }
172            
173             /* compute code point */
174 1           ucs = ((src[0] & 0x1F)<<6)|(src[1] & 0x3F);
175 1           src += utf8_len;
176 1 50         if( ucs_min<=ucs && ucs<=ucs_max )
    0          
177             { /* noop */
178             }else
179             { /* illegal sequence */
180 1 50         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
181 1           continue;
182             }
183            
184             /* ok. */
185 4 50         }else if( 0xe0<=*src && *src<=0xef )
    100          
186 0           { /* length [3] */
187 1           const int utf8_len = 3;
188 1           const UJ_UINT32 ucs_min = 0x800;
189 1           const UJ_UINT32 ucs_max = 0xffff;
190 1 50         if( src+2>=src_end ||
191 1 50         src[1]<0x80 || 0xbf
    50          
192 1 50         src[2]<0x80 || 0xbf
    50          
193             {
194 0 0         SV_Buf_append_ch2(&result,htons(*src));
    0          
    0          
195 0           ++src;
196 0           continue;
197             }
198            
199             /* compute code point */
200 1           ucs = ((src[0] & 0x0F)<<12)|((src[1] & 0x3F)<<6)|(src[2] & 0x3F);
201 1           src += utf8_len;
202 1 50         if( ucs_min<=ucs && ucs<=ucs_max )
    0          
203             { /* noop */
204             }else
205             { /* illegal sequence */
206 1 50         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
207 1           continue;
208             }
209            
210 0 0         if( ucs<0xD800 || ucs>0xDBFF )
    0          
211             { /* normal char, noop */
212             }else
213             { /* delete surrogate pair range */
214 0 0         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
215 0           continue;
216             }
217            
218             /* ok. */
219 3 50         }else if( 0xf0<=*src && *src<=0xf7 )
    100          
220             { /* length [4] */
221 1           const int utf8_len = 4;
222 1           const UJ_UINT32 ucs_min = 0x010000;
223 1           const UJ_UINT32 ucs_max = 0x10ffff;
224 1 50         if( src+3>=src_end ||
225 1 50         src[1]<0x80 || 0xbf
    50          
226 1 50         src[2]<0x80 || 0xbf
    50          
227 1 50         src[3]<0x80 || 0xbf
    50          
228             {
229 0 0         SV_Buf_append_ch2(&result,htons(*src));
    0          
    0          
230 0           ++src;
231 0           continue;
232             }
233            
234             /* compute code point */
235 1           ucs = ((src[0] & 0x07)<<18)|((src[1] & 0x3F)<<12)|
236 1           ((src[2] & 0x3f) << 6)|(src[3] & 0x3F);
237 1           src += utf8_len;
238 1 50         if( ucs_min<=ucs && ucs<=ucs_max )
    0          
239             { /* noop */
240             }else
241             { /* illegal sequence */
242 1 50         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
243 1           continue;
244             }
245            
246             #if ENABLE_SURROGATE_PAIR
247 0           { /* encode surrogate pair */
248 0           const UJ_UINT32 surrogate = ucs - 0x010000;
249 0 0         SV_Buf_append_ch2(&result,htons(((surrogate>>10)&0x03FF)|0xD800));
    0          
    0          
250 0 0         SV_Buf_append_ch2(&result,htons(((surrogate )&0x03FF)|0xDC00));
    0          
    0          
251 0           continue;
252             }
253             #else
254             { /* not supported */
255             SV_Buf_append_ch2(&result,htons('?'));
256             continue;
257             }
258             #endif
259            
260             /* ok. */
261 2 50         }else if( 0xf8<=*src && *src<=0xfb )
    100          
262 1           {
263 1           const int utf8_len = 5;
264 1 50         if( src+utf8_len<=src_end )
265             { /* noop */
266             }else
267             { /* no enough sequence */
268 0 0         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
269 0           ++src;
270 0           continue;
271             }
272             /* check follow sequences */
273 1 50         if( 0x80<=src[1] && src[1]<=0xbf && 0x80<=src[2] && src[2]<=0xbf
    50          
    50          
    50          
274 1 50         && 0x80<=src[3] && src[3]<=0xbf && 0x80<=src[4] && src[4]<=0xbf )
    50          
    50          
    50          
275             { /* noop */
276             }else
277             {
278 0 0         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
279 0           ++src;
280 0           continue;
281             }
282            
283             /* compute code point */
284 1           src += utf8_len;
285 1 50         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
286 1           continue;
287 1 50         }else if( 0xfc<=*src && *src<=0xfd )
    50          
288 1           {
289 1           const int utf8_len = 6;
290 1 50         if( src+utf8_len<=src_end )
291             { /* noop */
292             }else
293             { /* no enough sequence */
294 0 0         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
295 0           ++src;
296 0           continue;
297             }
298             /* check follow sequences */
299 1 50         if( 0x80<=src[1] && src[1]<=0xbf && 0x80<=src[2] && src[2]<=0xbf
    50          
    50          
    50          
300 1 50         && 0x80<=src[3] && src[3]<=0xbf && 0x80<=src[4] && src[4]<=0xbf
    50          
    50          
    50          
301 1 50         && 0x80<=src[5] && src[5]<=0xbf )
    50          
302             { /* noop */
303             }else
304             {
305 0 0         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
306 0           ++src;
307 0           continue;
308             }
309            
310             /* compute code point */
311 1           src += utf8_len;
312 1 50         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
313 1           continue;
314             }else
315             { /* invalid */
316 0 0         SV_Buf_append_ch2(&result,htons(*src));
    0          
    0          
317 0           ++src;
318 0           continue;
319             }
320              
321 0 0         if( ucs & ~0xFFFF )
322             { /* utf16¤ÎÈϰϳ° (ucs4¤ÎÈϰÏ) */
323 0 0         SV_Buf_append_ch2(&result,htons('?'));
    0          
    0          
324 0           continue;
325             }
326 0 0         SV_Buf_append_ch2(&result,htons(ucs));
    0          
    0          
327             /*bin_dump("now",dst_begin,dst-dst_begin); */
328             }
329              
330             /*bin_dump("out",result.getBegin(),result.getLength()); */
331 6           SV_Buf_setLength(&result);
332              
333 6           return SV_Buf_getSv(&result);
334             }
335              
336             /* ----------------------------------------------------------------------------
337             * End Of File.
338             * ------------------------------------------------------------------------- */