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