1 /*$
2 Copyright (C) 2013-2020 Azel.
3
4 This file is part of AzPainter.
5
6 AzPainter is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 AzPainter is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 $*/
19
20 /**********************************************
21 * [文字コード関連ユーティリティ]
22 **********************************************/
23
24 #include <string.h>
25 #include <stdlib.h>
26 #include <wchar.h>
27
28 #include "mDef.h"
29 #include "mUtilCharCode.h"
30
31
32 //-------------------------
33
34 static const uint8_t g_utf8_charwidth[128] =
35 {
36 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
37 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
38 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
39 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
40 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
41 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
42 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2,
43 3,3,3,3, 3,3,3,3, 4,4,4,4, 5,5,6,1
44 };
45
46 //-------------------------
47
48
49 /**
50 @defgroup util_charcode mUtilCharCode
51 @brief 文字コード関連ユーティリティ
52
53 @ingroup group_util
54
55 @{
56 @file mUtilCharCode.h
57 */
58
59
60 //=============================
61 // UTF-8
62 //=============================
63
64
65 /** UTF-8 の1文字のバイト数取得 */
66
mUTF8CharWidth(const char * p)67 int mUTF8CharWidth(const char *p)
68 {
69 return g_utf8_charwidth[(*(uint8_t *)p) >> 1];
70 }
71
72 /** UTF-8 から UCS-4 へ1文字変換
73 *
74 * @param maxlen src の1文字の最大長さ (負の値で自動)
75 * @param ppnext src の次の文字の位置が格納される (NULL 可)
76 * @retval 0 成功
77 * @retval 1 範囲外の文字など、処理は行わずスキップする文字
78 * @retval -1 エラー */
79
mUTF8ToUCS4Char(const char * src,int maxlen,uint32_t * dst,const char ** ppnext)80 int mUTF8ToUCS4Char(const char *src,int maxlen,uint32_t *dst,const char **ppnext)
81 {
82 const uint8_t *ps = (const uint8_t *)src;
83 uint32_t c;
84 int len,ret = 0;
85
86 if(maxlen < 0) maxlen = 4;
87
88 c = *ps;
89
90 if(c <= 0x7f)
91 {
92 if(maxlen < 1) return -1;
93 len = 1;
94 }
95 else if((c & 0xe0) == 0xc0)
96 {
97 //2byte : U+0080 - U+07FF
98
99 if(maxlen < 2) return -1;
100 if((ps[1] & 0xc0) != 0x80) return -1;
101
102 c = ((c & 0x1f) << 6) | (ps[1] & 0x3f);
103
104 if(c < 0x80) ret = 1;
105
106 len = 2;
107 }
108 else if((c & 0xf0) == 0xe0)
109 {
110 //3byte : U+0800 - U+FFFF (サロゲートエリア U+D800-U+DFFF は除く)
111
112 if(maxlen < 3) return -1;
113 if((ps[1] & 0xc0) != 0x80 || (ps[2] & 0xc0) != 0x80)
114 return -1;
115
116 c = ((c & 0x0f) << 12) | ((ps[1] & 0x3f) << 6) | (ps[2] & 0x3f);
117
118 if(c < 0x800 || (c >= 0xd800 && c <= 0xdfff)) ret = 1;
119 if(c == 0xfeff) ret = 1; //BOM
120
121 len = 3;
122 }
123 else if((c & 0xf8) == 0xf0)
124 {
125 //4byte : U+10000 - U+1FFFFF
126
127 if(maxlen < 4) return -1;
128 if((ps[1] & 0xc0) != 0x80 || (ps[2] & 0xc0) != 0x80 || (ps[3] & 0xc0) != 0x80)
129 return -1;
130
131 c = ((c & 0x07) << 18) | ((ps[1] & 0x3f) << 12) | ((ps[2] & 0x3f) << 6) | (ps[3] & 0x3f);
132
133 if(c < 0x10000 || c >= 0x10ffff) ret = 1;
134
135 len = 4;
136 }
137 else
138 return -1;
139
140 //
141
142 *dst = c;
143
144 if(ppnext) *ppnext = src + len;
145
146 return ret;
147 }
148
149 /** UTF-8 文字列を UCS-4 文字列に変換
150 *
151 * NULL 文字が追加できる場合は、最後に NULL 文字を追加する。
152 *
153 * @param srclen 負の値で NULL 文字まで
154 * @param dst NULL で変換後の文字数のみ計算
155 * @param dstlen NULL 文字も含む長さ。dst が NULL の場合は無視。
156 * @return 変換した文字数 (NULL 文字は含まない)。-1 でエラー */
157
mUTF8ToUCS4(const char * src,int srclen,uint32_t * dst,int dstlen)158 int mUTF8ToUCS4(const char *src,int srclen,uint32_t *dst,int dstlen)
159 {
160 const char *ps,*psend;
161 uint32_t uc;
162 int reslen = 0,ret;
163
164 if(srclen < 0) srclen = strlen(src);
165
166 ps = src;
167 psend = src + srclen;
168
169 while(*ps && ps - src < srclen)
170 {
171 if(dst && reslen >= dstlen) break;
172
173 ret = mUTF8ToUCS4Char(ps, psend - ps, &uc, &ps);
174
175 if(ret < 0) return -1;
176 if(ret > 0) continue;
177
178 if(dst) *(dst++) = uc;
179
180 reslen++;
181 }
182
183 if(dst && reslen < dstlen) *dst = 0;
184
185 return reslen;
186 }
187
188 /** UTF-8 文字列を UCS-4 文字列に変換 (メモリ確保)
189 *
190 * @param retlen NULL でなければ、結果の文字数が返る
191 * @return NULL でエラー */
192
mUTF8ToUCS4_alloc(const char * src,int srclen,int * retlen)193 uint32_t *mUTF8ToUCS4_alloc(const char *src,int srclen,int *retlen)
194 {
195 int len;
196 uint32_t *buf;
197
198 len = mUTF8ToUCS4(src, srclen, NULL, 0);
199 if(len < 0) return NULL;
200
201 buf = (uint32_t *)mMalloc((len + 1) << 2, FALSE);
202 if(!buf) return NULL;
203
204 mUTF8ToUCS4(src, srclen, buf, len + 1);
205
206 if(retlen) *retlen = len;
207
208 return buf;
209 }
210
211 /** UTF-8 文字列をワイド文字列に変換
212 *
213 * NULL 文字が追加できる場合は、最後に NULL 文字を追加する。
214 *
215 * @param srclen 負の値で NULL 文字まで
216 * @param dst NULL で変換後の文字数のみ計算
217 * @param dstlen NULL 文字も含む長さ。dst が NULL の場合は無視。
218 * @return 変換した文字数 (NULL 文字は含まない)。-1 でエラー */
219
mUTF8ToWide(const char * src,int srclen,wchar_t * dst,int dstlen)220 int mUTF8ToWide(const char *src,int srclen,wchar_t *dst,int dstlen)
221 {
222 const char *ps,*psend;
223 uint32_t wc;
224 int reslen = 0,ret;
225
226 if(srclen < 0) srclen = strlen(src);
227
228 ps = src;
229 psend = src + srclen;
230
231 while(*ps && ps - src < srclen)
232 {
233 if(dst && reslen >= dstlen) break;
234
235 ret = mUTF8ToUCS4Char(ps, psend - ps, &wc, &ps);
236
237 if(ret < 0) return -1;
238 if(ret > 0) continue;
239
240 if(wc > WCHAR_MAX) continue;
241
242 if(dst) *(dst++) = wc;
243
244 reslen++;
245 }
246
247 if(dst && reslen < dstlen) *dst = 0;
248
249 return reslen;
250 }
251
252 /** UTF-8 文字列をワイド文字列に変換 (メモリ確保)
253 *
254 * @param retlen NULL でなければ、結果の文字数が返る
255 * @return NULL でエラー */
256
mUTF8ToWide_alloc(const char * src,int srclen,int * retlen)257 wchar_t *mUTF8ToWide_alloc(const char *src,int srclen,int *retlen)
258 {
259 int len;
260 wchar_t *buf;
261
262 len = mUTF8ToWide(src, srclen, NULL, 0);
263 if(len < 0) return NULL;
264
265 buf = (wchar_t *)mMalloc(sizeof(wchar_t) * (len + 1), FALSE);
266 if(!buf) return NULL;
267
268 mUTF8ToWide(src, srclen, buf, len + 1);
269
270 if(retlen) *retlen = len;
271
272 return buf;
273 }
274
275 /** UTF-8 文字列をロケール文字列に変換
276 *
277 * NULL 文字が追加できる場合は、最後に NULL 文字を追加する。
278 *
279 * @param srclen 負の値で NULL 文字まで
280 * @param dst NULL で変換後のサイズのみ計算
281 * @param dstlen NULL 文字も含むサイズ。dst が NULL の場合は無視。
282 * @return 変換後のバッファサイズ (NULL 文字は含まない)。-1 でエラー */
283
mUTF8ToLocal(const char * src,int srclen,char * dst,int dstlen)284 int mUTF8ToLocal(const char *src,int srclen,char *dst,int dstlen)
285 {
286 const char *ps,*psEnd;
287 uint32_t wc;
288 char mb[MB_CUR_MAX];
289 mbstate_t state;
290 int nret,reslen = 0;
291 size_t wret;
292
293 if(srclen < 0) srclen = strlen(src);
294
295 ps = src;
296 psEnd = src + srclen;
297
298 memset(&state, 0, sizeof(mbstate_t));
299
300 while(*ps && ps - src < srclen)
301 {
302 //UTF8 -> UCS4
303
304 nret = mUTF8ToUCS4Char(ps, psEnd - ps, &wc, &ps);
305
306 if(nret < 0)
307 return -1;
308 else if(nret > 0 || wc > WCHAR_MAX)
309 continue;
310
311 //wchar_t -> local
312
313 wret = wcrtomb(mb, wc, &state);
314 if(wret == (size_t)-1) continue;
315
316 //セット
317
318 if(dst)
319 {
320 if(reslen + wret > dstlen) break;
321
322 memcpy(dst, mb, wret);
323 dst += wret;
324 }
325
326 reslen += wret;
327 }
328
329 if(dst && reslen < dstlen) *dst = 0;
330
331 return reslen;
332 }
333
334 /** UTF-8 文字列をロケール文字列に変換 (メモリ確保) */
335
mUTF8ToLocal_alloc(const char * src,int srclen,int * retlen)336 char *mUTF8ToLocal_alloc(const char *src,int srclen,int *retlen)
337 {
338 char *buf;
339 int len;
340
341 len = mUTF8ToLocal(src, srclen, NULL, 0);
342 if(len < 0) return NULL;
343
344 buf = (char *)mMalloc(len + 1, FALSE);
345 if(!buf) return NULL;
346
347 mUTF8ToLocal(src, srclen, buf, len + 1);
348
349 if(retlen) *retlen = len;
350
351 return buf;
352 }
353
354
355 //=============================
356 // ワイド文字列
357 //=============================
358
359
360 /** ワイド文字列を UTF-8 文字列に変換
361 *
362 * NULL 文字を付加する余裕がある場合、最後に NULL 文字を追加する。 @n
363 * 変換できない文字はスキップされる。
364 *
365 * @param srclen 負の値で NULL 文字まで
366 * @param dst NULL で変換後の文字数のみ計算
367 * @param dstlen NULL 文字も含む長さ。dst が NULL の場合は無視。
368 * @return 変換した UTF-8 文字列のバイト数 (NULL 文字は含まない) */
369
mWideToUTF8(const wchar_t * src,int srclen,char * dst,int dstlen)370 int mWideToUTF8(const wchar_t *src,int srclen,char *dst,int dstlen)
371 {
372 const wchar_t *ps;
373 char *pd;
374 int reslen = 0,len;
375
376 if(srclen < 0) srclen = wcslen(src);
377
378 ps = src;
379 pd = dst;
380
381 for(; *ps && srclen > 0; srclen--, ps++)
382 {
383 if(pd && reslen >= dstlen) break;
384
385 len = mUCS4ToUTF8Char(*ps, pd);
386
387 reslen += len;
388
389 if(pd) pd += len;
390 }
391
392 if(pd && reslen < dstlen) *pd = 0;
393
394 return reslen;
395 }
396
397 /** ワイド文字列を UTF-8 文字列に変換 (メモリを確保する)
398 *
399 * @param retlen NULL でなければ、結果の文字数が返る
400 * @return NULL でエラー */
401
mWideToUTF8_alloc(const wchar_t * src,int srclen,int * retlen)402 char *mWideToUTF8_alloc(const wchar_t *src,int srclen,int *retlen)
403 {
404 int len;
405 char *buf;
406
407 len = mWideToUTF8(src, srclen, NULL, 0);
408
409 buf = (char *)mMalloc(len + 1, FALSE);
410 if(!buf) return NULL;
411
412 mWideToUTF8(src, srclen, buf, len + 1);
413
414 if(retlen) *retlen = len;
415
416 return buf;
417 }
418
419
420 //=============================
421 // ロケール文字列
422 //=============================
423
424
425 /** ロケール文字列からワイド文字列に変換 */
426
mLocalToWide(const char * src,int srclen,wchar_t * dst,int dstlen)427 int mLocalToWide(const char *src,int srclen,wchar_t *dst,int dstlen)
428 {
429 const char *ps = src;
430 wchar_t *pd = dst;
431 mbstate_t state;
432 size_t ret;
433 wchar_t wc;
434 int len = 0;
435
436 if(srclen < 0) srclen = strlen(src);
437
438 memset(&state, 0, sizeof(mbstate_t));
439
440 while(*ps && ps - src < srclen)
441 {
442 if(pd && len >= dstlen) break;
443
444 ret = mbsrtowcs(&wc, &ps, 1, &state);
445 if(ret == 0 || ret == (size_t)-1) break;
446
447 if(pd) *(pd++) = wc;
448
449 len++;
450 }
451
452 if(pd && len < dstlen) *pd = 0;
453
454 return len;
455 }
456
457 /** ロケール文字列からワイド文字列に変換 (メモリ確保) */
458
mLocalToWide_alloc(const char * src,int srclen,int * retlen)459 wchar_t *mLocalToWide_alloc(const char *src,int srclen,int *retlen)
460 {
461 int len;
462 wchar_t *buf;
463
464 len = mLocalToWide(src, srclen, NULL, 0);
465 if(len < 0) return NULL;
466
467 buf = (wchar_t *)mMalloc(sizeof(wchar_t) * (len + 1), FALSE);
468 if(!buf) return NULL;
469
470 mLocalToWide(src, srclen, buf, len + 1);
471
472 if(retlen) *retlen = len;
473
474 return buf;
475 }
476
477 /** ロケール文字列から UTF-8 文字列に変換 (メモリ確保) */
478
mLocalToUTF8_alloc(const char * src,int srclen,int * retlen)479 char *mLocalToUTF8_alloc(const char *src,int srclen,int *retlen)
480 {
481 wchar_t *pwc;
482 char *utf8;
483 int len;
484
485 pwc = mLocalToWide_alloc(src, srclen, &len);
486 if(!pwc) return NULL;
487
488 utf8 = mWideToUTF8_alloc(pwc, len, retlen);
489
490 mFree(pwc);
491
492 return utf8;
493 }
494
495
496 //=============================
497 // UCS-4
498 //=============================
499
500
501 /** UCS-4 文字数取得 */
502
mUCS4Len(const uint32_t * p)503 int mUCS4Len(const uint32_t *p)
504 {
505 int i;
506
507 for(i = 0; *p; p++, i++);
508
509 return i;
510 }
511
512 /** UCS-4 文字列を複製 */
513
mUCS4StrDup(const uint32_t * src)514 uint32_t *mUCS4StrDup(const uint32_t *src)
515 {
516 if(!src)
517 return NULL;
518 else
519 {
520 uint32_t *buf;
521 int size;
522
523 size = 4 * (mUCS4Len(src) + 1);
524
525 buf = (uint32_t *)mMalloc(size, FALSE);
526 if(buf)
527 memcpy(buf, src, size);
528
529 return buf;
530 }
531 }
532
533 /** UCS-4 -> UTF-8 1文字変換
534 *
535 * @param dst NULL で必要なバイト数のみ取得。NULL 文字は追加されない。
536 * @return UTF-8 文字のバイト数。0 で変換なし。 */
537
mUCS4ToUTF8Char(uint32_t ucs,char * dst)538 int mUCS4ToUTF8Char(uint32_t ucs,char *dst)
539 {
540 uint8_t *pd = (uint8_t *)dst;
541
542 if(ucs < 0x80)
543 {
544 if(pd) *pd = ucs;
545
546 return 1;
547 }
548 else if(ucs <= 0x7ff)
549 {
550 if(pd)
551 {
552 pd[0] = 0xc0 | (ucs >> 6);
553 pd[1] = 0x80 | (ucs & 0x3f);
554 }
555
556 return 2;
557 }
558 else if(ucs <= 0xffff)
559 {
560 if(pd)
561 {
562 pd[0] = 0xe0 | (ucs >> 12);
563 pd[1] = 0x80 | ((ucs >> 6) & 0x3f);
564 pd[2] = 0x80 | (ucs & 0x3f);
565 }
566
567 return 3;
568 }
569 else if(ucs <= 0x1fffff)
570 {
571 if(pd)
572 {
573 pd[0] = 0xf0 | (ucs >> 18);
574 pd[1] = 0x80 | ((ucs >> 12) & 0x3f);
575 pd[2] = 0x80 | ((ucs >> 6) & 0x3f);
576 pd[3] = 0x80 | (ucs & 0x3f);
577 }
578
579 return 4;
580 }
581 else
582 return 0;
583 }
584
585 /** UCS-4 文字列から UTF-8 文字列に変換
586 *
587 * UCS-4 の変換できない文字はスキップされる。 @n
588 * NULL 文字を付加する余裕がある場合、NULL 文字が追加される。 */
589
mUCS4ToUTF8(const uint32_t * src,int srclen,char * dst,int dstlen)590 int mUCS4ToUTF8(const uint32_t *src,int srclen,char *dst,int dstlen)
591 {
592 char *pd = dst,m[6];
593 int len = 0,clen;
594
595 if(srclen < 0) srclen = mUCS4Len(src);
596
597 for(; *src && srclen > 0; src++, srclen--)
598 {
599 clen = mUCS4ToUTF8Char(*src, m);
600
601 if(pd && len + clen > dstlen) break;
602
603 if(pd)
604 {
605 memcpy(pd, m, clen);
606 pd += clen;
607 }
608
609 len += clen;
610 }
611
612 if(pd && len < dstlen) *pd = 0;
613
614 return len;
615 }
616
617 /** UCS-4 文字列から UTF-8 文字列に変換 (メモリ確保) */
618
mUCS4ToUTF8_alloc(const uint32_t * ucs,int srclen,int * retlen)619 char *mUCS4ToUTF8_alloc(const uint32_t *ucs,int srclen,int *retlen)
620 {
621 int i,len,dstlen = 0;
622 char *utf8,*pd;
623
624 if(!ucs) return NULL;
625
626 if(srclen < 0) srclen = mUCS4Len(ucs);
627
628 //サイズ
629
630 for(i = 0; *ucs && i < srclen; i++)
631 dstlen += mUCS4ToUTF8Char(ucs[i], NULL);
632
633 //確保
634
635 utf8 = (char *)mMalloc(dstlen + 1, FALSE);
636 if(!utf8) return NULL;
637
638 //変換
639
640 pd = utf8;
641
642 for(i = 0; *ucs && i < srclen; i++)
643 {
644 len = mUCS4ToUTF8Char(ucs[i], pd);
645 pd += len;
646 }
647
648 *pd = 0;
649
650 if(retlen) *retlen = dstlen;
651
652 return utf8;
653 }
654
655 /** UCS-4 文字列から wchar_t 文字列に変換 (メモリ確保) */
656
mUCS4ToWide_alloc(const uint32_t * src,int srclen,int * retlen)657 wchar_t *mUCS4ToWide_alloc(const uint32_t *src,int srclen,int *retlen)
658 {
659 const uint32_t *ps;
660 wchar_t *pwc;
661 int dlen;
662
663 if(srclen < 0) srclen = mUCS4Len(src);
664
665 pwc = (wchar_t *)mMalloc(sizeof(wchar_t) * (srclen + 1), FALSE);
666 if(!pwc) return NULL;
667
668 for(ps = src, dlen = 0; *ps && ps - src < srclen; ps++)
669 {
670 if(*ps <= WCHAR_MAX)
671 pwc[dlen++] = *ps;
672 }
673
674 pwc[dlen] = 0;
675
676 if(retlen) *retlen = dlen;
677
678 return pwc;
679 }
680
681 /** UCS-4 文字列を数値に変換
682 *
683 * 小数点以下は dig の桁数まで取得。
684 * dig = 1 なら 1.0 = 10 */
685
mUCS4ToFloatInt(const uint32_t * text,int dig)686 int mUCS4ToFloatInt(const uint32_t *text,int dig)
687 {
688 const uint32_t *p = text;
689 int fcnt = -1,n = 0;
690
691 if(*p == '-' || *p == '+') p++;
692
693 for(; *p; p++)
694 {
695 if(*p == '.')
696 {
697 if(dig <= 0 || fcnt != -1) break;
698
699 fcnt = 0;
700 }
701 else if(*p >= '0' && *p <= '9')
702 {
703 n *= 10;
704 n += *p - '0';
705
706 if(fcnt != -1)
707 {
708 fcnt++;
709 if(fcnt >= dig) break;
710 }
711 }
712 else
713 break;
714 }
715
716 //小数点以下の桁数が足りない場合
717
718 if(dig > 0 && fcnt < dig)
719 {
720 if(fcnt == -1) fcnt = 0;
721
722 for(; fcnt < dig; fcnt++, n *= 10);
723 }
724
725 if(*text == '-') n = -n;
726
727 return n;
728 }
729
730 /** UCS-4 文字列比較 */
731
mUCS4Compare(const uint32_t * text1,const uint32_t * text2)732 int mUCS4Compare(const uint32_t *text1,const uint32_t *text2)
733 {
734 //ポインタが NULL の時
735
736 if(!text1 && !text2)
737 return 0;
738 else if(!text1)
739 return -1;
740 else if(!text2)
741 return 1;
742
743 //比較
744
745 for(; *text1 && *text2 && *text1 == *text2; text1++, text2++);
746
747 if(*text1 == 0 && *text2 == 0)
748 return 0;
749 else
750 return (*text1 < *text2)? -1: 1;
751 }
752
753
754 //=============================
755 // UTF16
756 //=============================
757
758
759 /** UTF-16 文字列の長さ取得 */
760
mUTF16Len(const uint16_t * p)761 int mUTF16Len(const uint16_t *p)
762 {
763 int len = 0;
764
765 for(; *p; p++, len++);
766
767 return len;
768 }
769
770 /** UTF-16 から UCS-4 1文字取得
771 *
772 * @retval 0 成功
773 * @retval 1 無効な文字
774 * @retval -1 エラー */
775
mUTF16ToUCS4Char(const uint16_t * src,uint32_t * dst,const uint16_t ** ppnext)776 int mUTF16ToUCS4Char(const uint16_t *src,uint32_t *dst,const uint16_t **ppnext)
777 {
778 uint32_t c,c2;
779 int ret = 0;
780
781 c = *(src++);
782
783 if((c & 0xfc00) == 0xdc00)
784 ret = -1;
785 else if(c == 0xfeff) //BOM
786 ret = 1;
787 else if((c & 0xfc00) == 0xd800)
788 {
789 //32bit
790
791 c2 = *(src++);
792
793 if((c2 & 0xfc00) != 0xdc00)
794 ret = -1;
795 else
796 c = (((c & 0x03c0) + 0x40) << 10) | ((c & 0x3f) << 10) | (c2 & 0x3ff);
797 }
798
799 *dst = c;
800
801 if(ppnext) *ppnext = src;
802
803 return ret;
804 }
805
806 /** UTF-16 文字列を UTF-8 文字列に変換 */
807
mUTF16ToUTF8(const uint16_t * src,int srclen,char * dst,int dstlen)808 int mUTF16ToUTF8(const uint16_t *src,int srclen,char *dst,int dstlen)
809 {
810 const uint16_t *next;
811 char *pd;
812 uint32_t ucs;
813 int reslen = 0,len;
814
815 if(srclen < 0) srclen = mUTF16Len(src);
816
817 pd = dst;
818
819 while(*src && srclen > 0)
820 {
821 if(pd && reslen >= dstlen) break;
822
823 //UTF16 => UCS4
824
825 if(mUTF16ToUCS4Char(src, &ucs, &next)) break;
826
827 srclen -= next - src;
828 src = next;
829
830 //UCS4 => UTF8
831
832 len = mUCS4ToUTF8Char(ucs, pd);
833
834 reslen += len;
835 if(pd) pd += len;
836 }
837
838 if(pd && reslen < dstlen) *pd = 0;
839
840 return reslen;
841 }
842
843 /** UTF-16 文字列を UTF-8 文字列に変換 (確保) */
844
mUTF16ToUTF8_alloc(const uint16_t * src,int srclen,int * retlen)845 char *mUTF16ToUTF8_alloc(const uint16_t *src,int srclen,int *retlen)
846 {
847 int len;
848 char *buf;
849
850 len = mUTF16ToUTF8(src, srclen, NULL, 0);
851
852 buf = (char *)mMalloc(len + 1, FALSE);
853 if(!buf) return NULL;
854
855 mUTF16ToUTF8(src, srclen, buf, len + 1);
856
857 if(retlen) *retlen = len;
858
859 return buf;
860 }
861
862 /** @} */
863