1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Mayaqua Kernel
3 
4 
5 // Internat.c
6 // String conversion library for internationalization
7 
8 #include "Internat.h"
9 
10 #include "Mayaqua.h"
11 #include "Memory.h"
12 #include "Network.h"
13 #include "Object.h"
14 #include "Str.h"
15 #include "Tracking.h"
16 #include "Win32.h"
17 
18 #include <stdlib.h>
19 #include <wchar.h>
20 
21 #ifdef OS_UNIX
22 #include <iconv.h>
23 #endif
24 
25 extern LOCK *token_lock;
26 static char charset[MAX_SIZE] = "EUCJP";
27 static LOCK *iconv_lock = NULL;
28 void *iconv_cache_wide_to_str = 0;
29 void *iconv_cache_str_to_wide = 0;
30 
31 // Examine whether the string contains the specified character
UniInChar(wchar_t * string,wchar_t c)32 bool UniInChar(wchar_t *string, wchar_t c)
33 {
34 	UINT i, len;
35 	// Validate arguments
36 	if (string == NULL)
37 	{
38 		return false;
39 	}
40 
41 	len = UniStrLen(string);
42 
43 	for (i = 0;i < len;i++)
44 	{
45 		if (string[i] == c)
46 		{
47 			return true;
48 		}
49 	}
50 
51 	return false;
52 }
53 
54 // Check whether the string is included
UniInStr(wchar_t * str,wchar_t * keyword)55 bool UniInStr(wchar_t *str, wchar_t *keyword)
56 {
57 	return UniInStrEx(str, keyword, false);
58 }
UniInStrEx(wchar_t * str,wchar_t * keyword,bool case_sensitive)59 bool UniInStrEx(wchar_t *str, wchar_t *keyword, bool case_sensitive)
60 {
61 	// Validate arguments
62 	if (UniIsEmptyStr(str) || UniIsEmptyStr(keyword))
63 	{
64 		return false;
65 	}
66 
67 	if (UniSearchStrEx(str, keyword, 0, case_sensitive) == INFINITE)
68 	{
69 		return false;
70 	}
71 
72 	return true;
73 }
74 
75 // Convert to binary data
UniStrToBin(wchar_t * str)76 BUF *UniStrToBin(wchar_t *str)
77 {
78 	char *str_a = CopyUniToStr(str);
79 	BUF *ret;
80 
81 	ret = StrToBin(str_a);
82 
83 	Free(str_a);
84 
85 	return ret;
86 }
87 
88 // Check whether the character is safe
UniIsSafeChar(wchar_t c)89 bool UniIsSafeChar(wchar_t c)
90 {
91 	UINT i, len;
92 	wchar_t *check_str =
93 		L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
94 		L"abcdefghijklmnopqrstuvwxyz"
95 		L"0123456789"
96 		L" ()-_#%&.";
97 
98 	len = UniStrLen(check_str);
99 	for (i = 0;i < len;i++)
100 	{
101 		if (c == check_str[i])
102 		{
103 			return true;
104 		}
105 	}
106 	return false;
107 }
108 
109 // Convert a string list to a token list
UniListToTokenList(LIST * o)110 UNI_TOKEN_LIST *UniListToTokenList(LIST *o)
111 {
112 	UINT i;
113 	UNI_TOKEN_LIST *t;
114 	// Validate arguments
115 	if (o == NULL)
116 	{
117 		return NULL;
118 	}
119 
120 	t = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
121 	t->NumTokens = LIST_NUM(o);
122 	t->Token = ZeroMalloc(sizeof(wchar_t *) * t->NumTokens);
123 	for (i = 0;i < LIST_NUM(o);i++)
124 	{
125 		t->Token[i] = UniCopyStr(LIST_DATA(o, i));
126 	}
127 
128 	return t;
129 }
130 
131 // Free the string list
UniFreeStrList(LIST * o)132 void UniFreeStrList(LIST *o)
133 {
134 	UINT i;
135 	// Validate arguments
136 	if (o == NULL)
137 	{
138 		return;
139 	}
140 
141 	for (i = 0;i < LIST_NUM(o);i++)
142 	{
143 		wchar_t *s = LIST_DATA(o, i);
144 		Free(s);
145 	}
146 
147 	ReleaseList(o);
148 }
149 
150 // Normalize the line breaks
UniNormalizeCrlf(wchar_t * str)151 wchar_t *UniNormalizeCrlf(wchar_t *str)
152 {
153 	wchar_t *ret;
154 	UINT ret_size, i, len, wp;
155 	// Validate arguments
156 	if (str == NULL)
157 	{
158 		return NULL;
159 	}
160 
161 	len = UniStrLen(str);
162 	ret_size = sizeof(wchar_t) * (len + 32) * 2;
163 	ret = Malloc(ret_size);
164 
165 	wp = 0;
166 
167 	for (i = 0;i < len;i++)
168 	{
169 		wchar_t c = str[i];
170 
171 		switch (c)
172 		{
173 		case L'\r':
174 			if (str[i + 1] == L'\n')
175 			{
176 				i++;
177 			}
178 			ret[wp++] = L'\r';
179 			ret[wp++] = L'\n';
180 			break;
181 
182 		case L'\n':
183 			ret[wp++] = L'\r';
184 			ret[wp++] = L'\n';
185 			break;
186 
187 		default:
188 			ret[wp++] = c;
189 			break;
190 		}
191 	}
192 
193 	ret[wp++] = 0;
194 
195 	return ret;
196 }
197 
198 // Check whether str ends with the key
UniEndWith(wchar_t * str,wchar_t * key)199 bool UniEndWith(wchar_t *str, wchar_t *key)
200 {
201 	UINT str_len;
202 	UINT key_len;
203 	// Validate arguments
204 	if (str == NULL || key == NULL)
205 	{
206 		return false;
207 	}
208 
209 	// Comparison
210 	str_len = UniStrLen(str);
211 	key_len = UniStrLen(key);
212 	if (str_len < key_len)
213 	{
214 		return false;
215 	}
216 
217 	if (UniStrCmpi(str + (str_len - key_len), key) == 0)
218 	{
219 		return true;
220 	}
221 	else
222 	{
223 		return false;
224 	}
225 }
226 
227 // Check whether str starts with the key
UniStartWith(wchar_t * str,wchar_t * key)228 bool UniStartWith(wchar_t *str, wchar_t *key)
229 {
230 	UINT str_len;
231 	UINT key_len;
232 	wchar_t *tmp;
233 	bool ret;
234 	// Validate arguments
235 	if (str == NULL || key == NULL)
236 	{
237 		return false;
238 	}
239 
240 	// Comparison
241 	str_len = UniStrLen(str);
242 	key_len = UniStrLen(key);
243 	if (str_len < key_len)
244 	{
245 		return false;
246 	}
247 	if (str_len == 0 || key_len == 0)
248 	{
249 		return false;
250 	}
251 	tmp = CopyUniStr(str);
252 	tmp[key_len] = 0;
253 
254 	if (UniStrCmpi(tmp, key) == 0)
255 	{
256 		ret = true;
257 	}
258 	else
259 	{
260 		ret = false;
261 	}
262 
263 	Free(tmp);
264 
265 	return ret;
266 }
267 
268 // Convert the integer to a comma-separated string
UniToStr3(wchar_t * str,UINT size,UINT64 value)269 void UniToStr3(wchar_t *str, UINT size, UINT64 value)
270 {
271 	char tmp[MAX_SIZE];
272 	// Validate arguments
273 	if (str == NULL)
274 	{
275 		return;
276 	}
277 
278 	ToStr3(tmp, sizeof(tmp), value);
279 
280 	StrToUni(str, size, tmp);
281 }
282 
283 // Format of the string (internal function)
InternalFormatArgs(wchar_t * fmt,va_list args,bool ansi_mode)284 wchar_t *InternalFormatArgs(wchar_t *fmt, va_list args, bool ansi_mode)
285 {
286 	UINT i, len;
287 	wchar_t *tmp;
288 	UINT tmp_size;
289 	LIST *o;
290 	UINT mode = 0;
291 	UINT wp;
292 	UINT total_size;
293 	wchar_t *ret;
294 	// Validate arguments
295 	if (fmt == NULL)
296 	{
297 		return NULL;
298 	}
299 
300 	len = UniStrLen(fmt);
301 	tmp_size = UniStrSize(fmt);
302 	tmp = Malloc(tmp_size);
303 
304 	o = NewListFast(NULL);
305 
306 	mode = 0;
307 
308 	wp = 0;
309 
310 	for (i = 0;i < len;i++)
311 	{
312 		wchar_t c = fmt[i];
313 
314 		if (mode == 0)
315 		{
316 			// Normal character mode
317 			switch (c)
318 			{
319 			case L'%':
320 				// The start of the format specification
321 				if (fmt[i + 1] == L'%')
322 				{
323 					// If the next character is also '%', output a '%' simply
324 					i++;
325 					tmp[wp++] = c;
326 				}
327 				else
328 				{
329 					// Shift the state if the next character is not a '%'
330 					mode = 1;
331 					tmp[wp++] = 0;
332 					wp = 0;
333 					Add(o, CopyUniStr(tmp));
334 					tmp[wp++] = c;
335 				}
336 				break;
337 			default:
338 				// Ordinary character
339 				tmp[wp++] = c;
340 				break;
341 			}
342 		}
343 		else
344 		{
345 			char *tag;
346 			char dst[MAX_SIZE];
347 			wchar_t *target_str;
348 			wchar_t *padding_str;
349 			bool left_padding;
350 			UINT target_str_len;
351 			UINT total_len;
352 			wchar_t *output_str;
353 			UINT padding;
354 			// Formatting mode
355 			switch (c)
356 			{
357 			case L'c':
358 			case L'C':
359 			case L'd':
360 			case L'i':
361 			case L'o':
362 			case L'u':
363 			case L'x':
364 			case L'X':
365 				// int type
366 				tmp[wp++] = c;
367 				tmp[wp++] = 0;
368 				tag = CopyUniToStr(tmp);
369 
370 				#ifdef	OS_WIN32
371 					ReplaceStrEx(tag, 0, tag, "ll", "I64", false);
372 				#else	// OS_WIN32
373 					ReplaceStrEx(tag, 0, tag, "I64", "ll", false);
374 				#endif	// OS_WIN32
375 
376 				if ((UniStrLen(tmp) >= 5 && tmp[UniStrLen(tmp) - 4] == L'I' &&
377 					tmp[UniStrLen(tmp) - 3] == L'6' &&
378 					tmp[UniStrLen(tmp) - 2] == L'4') ||
379 					(
380 					UniStrLen(tmp) >= 4 && tmp[UniStrLen(tmp) - 3] == L'l' &&
381 					tmp[UniStrLen(tmp) - 2] == L'l'))
382 				{
383 					#ifdef	OS_WIN32
384 						_snprintf(dst, sizeof(dst), tag, va_arg(args, UINT64));
385 					#else	// OS_WIN32
386 						snprintf(dst, sizeof(dst), tag, va_arg(args, UINT64));
387 					#endif	// OS_WIN32
388 				}
389 				else
390 				{
391 					#ifdef	OS_WIN32
392 						_snprintf(dst, sizeof(dst), tag, va_arg(args, int));
393 					#else	// OS_WIN32
394 						snprintf(dst, sizeof(dst), tag, va_arg(args, int));
395 					#endif	// OS_WIN32
396 				}
397 
398 				Free(tag);
399 				Add(o, CopyStrToUni(dst));
400 
401 				wp = 0;
402 				mode = 0;
403 				break;
404 			case L'e':
405 			case L'E':
406 			case L'f':
407 			case L'g':
408 			case L'G':
409 				// Double type
410 				tmp[wp++] = c;
411 				tmp[wp++] = 0;
412 				tag = CopyUniToStr(tmp);
413 
414 				#ifdef	OS_WIN32
415 					_snprintf(dst, sizeof(dst), tag, va_arg(args, double));
416 				#else	// OS_WIN32
417 					snprintf(dst, sizeof(dst), tag, va_arg(args, double));
418 				#endif	// OS_WIN32
419 
420 				Free(tag);
421 				Add(o, CopyStrToUni(dst));
422 
423 				wp = 0;
424 				mode = 0;
425 				break;
426 			case L'n':
427 			case L'p':
428 				// Pointer type
429 				tmp[wp++] = c;
430 				tmp[wp++] = 0;
431 				tag = ZeroMalloc(UniStrSize(tmp) + 32);
432 				UniToStr(tag, 0, tmp);
433 
434 				#ifdef	OS_WIN32
435 					_snprintf(dst, sizeof(dst), tag, va_arg(args, void *));
436 				#else	// OS_WIN32
437 					snprintf(dst, sizeof(dst), tag, va_arg(args, void *));
438 				#endif	// OS_WIN32
439 
440 				Free(tag);
441 				Add(o, CopyStrToUni(dst));
442 
443 				wp = 0;
444 				mode = 0;
445 				break;
446 			case L'r':
447 			case L'R':
448 				// IP address type
449 				tmp[wp++] = c;
450 				tmp[wp++] = 0;
451 
452 				Zero(dst, sizeof(dst));
453 				IPToStr(dst, sizeof(dst), va_arg(args, void *));
454 
455 				Add(o, CopyStrToUni(dst));
456 
457 				wp = 0;
458 				mode = 0;
459 				break;
460 
461 			case L's':
462 			case L'S':
463 				// String type
464 				tmp[wp++] = c;
465 				tmp[wp++] = 0;
466 
467 				if (ansi_mode == false)
468 				{
469 					if (c == L'S')
470 					{
471 						c = L's';
472 					}
473 					else
474 					{
475 						c = L'S';
476 					}
477 				}
478 
479 				if (c == L's')
480 				{
481 					target_str = CopyStrToUni(va_arg(args, char *));
482 				}
483 				else
484 				{
485 					target_str = CopyUniStr(va_arg(args, wchar_t *));
486 				}
487 
488 				if (target_str == NULL)
489 				{
490 					target_str = CopyUniStr(L"(null)");
491 				}
492 
493 				padding = 0;
494 				left_padding = false;
495 				if (tmp[1] == L'-')
496 				{
497 					// Left aligned
498 					if (UniStrLen(tmp) >= 3)
499 					{
500 						padding = UniToInt(&tmp[2]);
501 					}
502 					left_padding = true;
503 				}
504 				else
505 				{
506 					// Right aligned
507 					if (UniStrLen(tmp) >= 2)
508 					{
509 						padding = UniToInt(&tmp[1]);
510 					}
511 				}
512 
513 				target_str_len = UniStrWidth(target_str);
514 
515 				if (padding > target_str_len)
516 				{
517 					UINT len = padding - target_str_len;
518 					UINT i;
519 					padding_str = ZeroMalloc(sizeof(wchar_t) * (len + 1));
520 					for (i = 0;i < len;i++)
521 					{
522 						padding_str[i] = L' ';
523 					}
524 				}
525 				else
526 				{
527 					padding_str = ZeroMalloc(sizeof(wchar_t));
528 				}
529 
530 				total_len = sizeof(wchar_t) * (UniStrLen(padding_str) + UniStrLen(target_str) + 1);
531 				output_str = ZeroMalloc(total_len);
532 				output_str[0] = 0;
533 
534 				if (left_padding == false)
535 				{
536 					UniStrCat(output_str, total_len, padding_str);
537 				}
538 				UniStrCat(output_str, total_len, target_str);
539 				if (left_padding)
540 				{
541 					UniStrCat(output_str, total_len, padding_str);
542 				}
543 
544 				Add(o, output_str);
545 
546 				Free(target_str);
547 				Free(padding_str);
548 
549 				wp = 0;
550 				mode = 0;
551 				break;
552 			default:
553 				// Normal string
554 				tmp[wp++] = c;
555 				break;
556 			}
557 		}
558 	}
559 	tmp[wp++] = 0;
560 	wp = 0;
561 
562 	if (UniStrLen(tmp) >= 1)
563 	{
564 		Add(o, CopyUniStr(tmp));
565 	}
566 
567 	total_size = sizeof(wchar_t);
568 	for (i = 0;i < LIST_NUM(o);i++)
569 	{
570 		wchar_t *s = LIST_DATA(o, i);
571 		total_size += UniStrLen(s) * sizeof(wchar_t);
572 	}
573 
574 	ret = ZeroMalloc(total_size);
575 	for (i = 0;i < LIST_NUM(o);i++)
576 	{
577 		wchar_t *s = LIST_DATA(o, i);
578 		UniStrCat(ret, total_size, s);
579 		Free(s);
580 	}
581 
582 	ReleaseList(o);
583 
584 	Free(tmp);
585 
586 	return ret;
587 }
588 
589 // Get the width of the string
UniStrWidth(wchar_t * str)590 UINT UniStrWidth(wchar_t *str)
591 {
592 	UINT i, len, ret;
593 	// Validate arguments
594 	if (str == NULL)
595 	{
596 		return 0;
597 	}
598 
599 	ret = 0;
600 	len = UniStrLen(str);
601 	for (i = 0;i < len;i++)
602 	{
603 		if (str[i] <= 255)
604 		{
605 			ret++;
606 		}
607 		else
608 		{
609 			ret += 2;
610 		}
611 	}
612 	return ret;
613 }
614 
615 // Convert string of 2 byte/character to wchar_t of 4 byte/character
Utf16ToWide(USHORT * str)616 wchar_t *Utf16ToWide(USHORT *str)
617 {
618 	wchar_t *ret;
619 	UINT len, i;
620 	// Validate arguments
621 	if (str == NULL)
622 	{
623 		return NULL;
624 	}
625 
626 	len = 0;
627 	while (true)
628 	{
629 		if (str[len] == 0)
630 		{
631 			break;
632 		}
633 		len++;
634 	}
635 
636 	ret = Malloc((len + 1) * sizeof(wchar_t));
637 	for (i = 0;i < len + 1;i++)
638 	{
639 		ret[i] = (wchar_t)str[i];
640 	}
641 
642 	return ret;
643 }
644 
645 // Convert wchar_t string of 4 byte/character to string of 2 byte/character
WideToUtf16(wchar_t * str)646 USHORT *WideToUtf16(wchar_t *str)
647 {
648 	USHORT *ret;
649 	UINT len;
650 	UINT ret_size;
651 	UINT i;
652 	// Validate arguments
653 	if (str == NULL)
654 	{
655 		return NULL;
656 	}
657 
658 	len = UniStrLen(str);
659 
660 	ret_size = (len + 1) * 2;
661 	ret = Malloc(ret_size);
662 
663 	for (i = 0;i < len + 1;i++)
664 	{
665 		ret[i] = (USHORT)str[i];
666 	}
667 
668 	return ret;
669 }
670 
671 // Initialization of the International Library
InitInternational()672 void InitInternational()
673 {
674 #ifdef	OS_UNIX
675 	void *d;
676 
677 	if (iconv_lock != NULL)
678 	{
679 		return;
680 	}
681 
682 	GetCurrentCharSet(charset, sizeof(charset));
683 	d = IconvWideToStrInternal();
684 	if (d == (void *)-1)
685 	{
686 #if defined (UNIX_MACOS) || defined (UNIX_LINUX_MUSL)
687 		StrCpy(charset, sizeof(charset), "utf-8");
688 #else // defined (UNIX_MACOS) || defined (UNIX_LINUX_MUSL)
689 		StrCpy(charset, sizeof(charset), "EUCJP");
690 #endif // defined (UNIX_MACOS) || defined (UNIX_LINUX_MUSL)
691 		d = IconvWideToStrInternal();
692 		if (d == (void *)-1)
693 		{
694 			StrCpy(charset, sizeof(charset), "US");
695 		}
696 		else
697 		{
698 			IconvFreeInternal(d);
699 		}
700 	}
701 	else
702 	{
703 		IconvFreeInternal(d);
704 	}
705 
706 	iconv_lock = NewLockMain();
707 
708 	iconv_cache_wide_to_str = IconvWideToStrInternal();
709 	iconv_cache_str_to_wide = IconvStrToWideInternal();
710 #endif	// OS_UNIX
711 }
712 
713 // Release of the International Library
FreeInternational()714 void FreeInternational()
715 {
716 #ifdef	OS_UNIX
717 #endif	// OS_UNIX
718 }
719 
720 #ifdef	OS_UNIX
721 
722 // Calculate the size when the string converted to Unicode
UnixCalcStrToUni(char * str)723 UINT UnixCalcStrToUni(char *str)
724 {
725 	wchar_t *tmp;
726 	UINT len, tmp_size;
727 	UINT ret;
728 	// Validate arguments
729 	if (str == NULL)
730 	{
731 		return 0;
732 	}
733 
734 	len = StrLen(str);
735 	tmp_size = len * 5 + 10;
736 	tmp = ZeroMalloc(tmp_size);
737 	UnixStrToUni(tmp, tmp_size, str);
738 	ret = UniStrLen(tmp);
739 	Free(tmp);
740 
741 	return (ret + 1) * sizeof(wchar_t);
742 }
743 
744 // Convert the strings to Unicode
UnixStrToUni(wchar_t * s,UINT size,char * str)745 UINT UnixStrToUni(wchar_t *s, UINT size, char *str)
746 {
747 	void *d;
748 	char *inbuf;
749 	size_t insize;
750 	char *outbuf;
751 	char *outbuf_orig;
752 	size_t outsize;
753 	wchar_t *tmp;
754 	// Validate arguments
755 	if (s == NULL || str == NULL)
756 	{
757 		return 0;
758 	}
759 
760 	d = IconvStrToWide();
761 	if (d == (void *)-1)
762 	{
763 		UniStrCpy(s, size, L"");
764 		return 0;
765 	}
766 
767 	inbuf = (char *)str;
768 	insize = StrLen(str) + 1;
769 	outsize = insize * 5 + 10;
770 	outbuf_orig = outbuf = ZeroMalloc(outsize);
771 
772 	if (iconv((iconv_t)d, (char **)&inbuf, (size_t *)&insize, (char **)&outbuf, (size_t *)&outsize) == (size_t)(-1))
773 	{
774 		Free(outbuf_orig);
775 		UniStrCpy(s, size, L"");
776 		IconvFree(d);
777 		return 0;
778 	}
779 
780 	tmp = Utf16ToWide((USHORT *)outbuf_orig);
781 	Free(outbuf_orig);
782 
783 	UniStrCpy(s, size, tmp);
784 	IconvFree(d);
785 
786 	Free(tmp);
787 
788 	return UniStrLen(s);
789 }
790 
791 // Calculate the size when the Unicode converted to string
UnixCalcUniToStr(wchar_t * s)792 UINT UnixCalcUniToStr(wchar_t *s)
793 {
794 	char *tmp;
795 	UINT tmp_size;
796 	UINT ret;
797 	// Validate arguments
798 	if (s == NULL)
799 	{
800 		return 0;
801 	}
802 
803 	tmp_size = UniStrLen(s) * 5 + 10;
804 	tmp = ZeroMalloc(tmp_size);
805 	UnixUniToStr(tmp, tmp_size, s);
806 
807 	ret = StrSize(tmp);
808 	Free(tmp);
809 
810 	return ret;
811 }
812 
813 // Converted a Unicode string to a string
UnixUniToStr(char * str,UINT size,wchar_t * s)814 UINT UnixUniToStr(char *str, UINT size, wchar_t *s)
815 {
816 	USHORT *tmp;
817 	char *inbuf;
818 	size_t insize;
819 	char *outbuf;
820 	char *outbuf_orig;
821 	size_t outsize;
822 	void *d;
823 	// Validate arguments
824 	if (str == NULL || s == NULL)
825 	{
826 		return 0;
827 	}
828 
829 	// Convert a wchar_t string to sequence of 2-bytes first
830 	tmp = WideToUtf16(s);
831 	inbuf = (char *)tmp;
832 	insize = (UniStrLen(s) + 1) * 2;
833 	outsize = insize * 5 + 10;
834 	outbuf_orig = outbuf = ZeroMalloc(outsize);
835 
836 	d = IconvWideToStr();
837 	if (d == (void *)-1)
838 	{
839 		StrCpy(str, size, "");
840 		Free(outbuf);
841 		Free(tmp);
842 		return 0;
843 	}
844 
845 	if (iconv((iconv_t)d, (char **)&inbuf, (size_t *)&insize, (char **)&outbuf, (size_t *)&outsize) == (size_t)(-1))
846 	{
847 		Free(outbuf_orig);
848 		IconvFree(d);
849 		StrCpy(str, size, "");
850 		Free(tmp);
851 		return 0;
852 	}
853 
854 	StrCpy(str, size, outbuf_orig);
855 
856 	Free(outbuf_orig);
857 	IconvFree(d);
858 	Free(tmp);
859 
860 	return StrLen(str);
861 }
862 
863 // Converted the whcar_t to char
IconvWideToStrInternal()864 void *IconvWideToStrInternal()
865 {
866 	return (void *)iconv_open(charset, IsBigEndian() ? "UTF-16BE" : "UTF-16LE");
867 }
868 
869 // Convert the char to a wchar_t
IconvStrToWideInternal()870 void *IconvStrToWideInternal()
871 {
872 	return (void *)iconv_open(IsBigEndian() ? "UTF-16BE" : "UTF-16LE", charset);
873 }
874 
875 // Close the handle
IconvFreeInternal(void * d)876 int IconvFreeInternal(void *d)
877 {
878 	iconv_close((iconv_t)d);
879 	return 0;
880 }
881 
IconvWideToStr()882 void *IconvWideToStr()
883 {
884 	if (iconv_cache_wide_to_str == (void *)-1)
885 	{
886 		return (void *)-1;
887 	}
888 
889 	Lock(iconv_lock);
890 
891 	return iconv_cache_wide_to_str;
892 }
893 
IconvStrToWide()894 void *IconvStrToWide()
895 {
896 	if (iconv_cache_str_to_wide == (void *)-1)
897 	{
898 		return (void *)-1;
899 	}
900 
901 	Lock(iconv_lock);
902 
903 	return iconv_cache_str_to_wide;
904 }
905 
IconvFree(void * d)906 int IconvFree(void *d)
907 {
908 	Unlock(iconv_lock);
909 
910 	return 0;
911 }
912 
913 // Get the character set that is currently used from the environment variable
GetCurrentCharSet(char * name,UINT size)914 void GetCurrentCharSet(char *name, UINT size)
915 {
916 	char tmp[MAX_SIZE];
917 	TOKEN_LIST *t;
918 	// Validate arguments
919 	if (name == NULL)
920 	{
921 		return;
922 	}
923 
924 	Zero(tmp, sizeof(tmp));
925 	if (GetEnv("LANG", tmp, sizeof(tmp)) == false || IsEmptyStr(tmp))
926 	{
927 		Zero(tmp, sizeof(tmp));
928 		if (GetEnv("LOCATION", tmp, sizeof(tmp)) == false || IsEmptyStr(tmp))
929 		{
930 			StrCpy(tmp, sizeof(tmp), "C");
931 		}
932 	}
933 
934 	Trim(tmp);
935 
936 	t = ParseToken(tmp, ".");
937 	if (t->NumTokens >= 2)
938 	{
939 		StrCpy(name, size, t->Token[1]);
940 	}
941 	else
942 	{
943 		if (t->NumTokens == 1)
944 		{
945 			StrCpy(name, size, t->Token[0]);
946 		}
947 		else
948 		{
949 			StrCpy(name, size, "eucJP");
950 		}
951 	}
952 	FreeToken(t);
953 
954 	StrUpper(name);
955 }
956 
957 #endif	// OS_UNIX
958 
959 // Check whether the specified string is a space
UniIsEmptyStr(wchar_t * str)960 bool UniIsEmptyStr(wchar_t *str)
961 {
962 	return IsEmptyUniStr(str);
963 }
IsEmptyUniStr(wchar_t * str)964 bool IsEmptyUniStr(wchar_t *str)
965 {
966 	bool ret;
967 	wchar_t *s;
968 	// Validate arguments
969 	if (str == NULL)
970 	{
971 		return true;
972 	}
973 
974 	s = UniCopyStr(str);
975 
976 	UniTrim(s);
977 	if (UniStrLen(s) == 0)
978 	{
979 		ret = true;
980 	}
981 	else
982 	{
983 		ret = false;
984 	}
985 
986 	Free(s);
987 
988 	return ret;
989 }
990 
991 // Check whether the specified string is a number
UniIsNum(wchar_t * str)992 bool UniIsNum(wchar_t *str)
993 {
994 	char tmp[MAX_SIZE];
995 
996 	// Validate arguments
997 	if (str == NULL)
998 	{
999 		return false;
1000 	}
1001 
1002 	UniToStrForSingleChars(tmp, sizeof(tmp), str);
1003 
1004 	return IsNum(tmp);
1005 }
1006 
1007 
1008 // Empty Unicode token list
UniNullToken()1009 UNI_TOKEN_LIST *UniNullToken()
1010 {
1011 	UNI_TOKEN_LIST *ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
1012 	ret->Token = ZeroMalloc(0);
1013 
1014 	return ret;
1015 }
1016 
1017 // Convert the token list to Unicode token list
TokenListToUniTokenList(TOKEN_LIST * src)1018 UNI_TOKEN_LIST *TokenListToUniTokenList(TOKEN_LIST *src)
1019 {
1020 	UNI_TOKEN_LIST *ret;
1021 	UINT i;
1022 	// Validate arguments
1023 	if (src == NULL)
1024 	{
1025 		return NULL;
1026 	}
1027 
1028 	ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
1029 	ret->NumTokens = src->NumTokens;
1030 	ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
1031 
1032 	for (i = 0;i < ret->NumTokens;i++)
1033 	{
1034 		ret->Token[i] = CopyStrToUni(src->Token[i]);
1035 	}
1036 
1037 	return ret;
1038 }
1039 
1040 // Convert a Unicode token list to a token list
UniTokenListToTokenList(UNI_TOKEN_LIST * src)1041 TOKEN_LIST *UniTokenListToTokenList(UNI_TOKEN_LIST *src)
1042 {
1043 	TOKEN_LIST *ret;
1044 	UINT i;
1045 	// Validate arguments
1046 	if (src == NULL)
1047 	{
1048 		return NULL;
1049 	}
1050 
1051 	ret = ZeroMalloc(sizeof(TOKEN_LIST));
1052 	ret->NumTokens = src->NumTokens;
1053 	ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
1054 
1055 	for (i = 0;i < ret->NumTokens;i++)
1056 	{
1057 		ret->Token[i] = CopyUniToStr(src->Token[i]);
1058 	}
1059 
1060 	return ret;
1061 }
1062 
1063 // Unicode string copy
UniCopyStr(wchar_t * str)1064 wchar_t *UniCopyStr(wchar_t *str)
1065 {
1066 	return CopyUniStr(str);
1067 }
1068 
1069 // Copy the token list
UniCopyToken(UNI_TOKEN_LIST * src)1070 UNI_TOKEN_LIST *UniCopyToken(UNI_TOKEN_LIST *src)
1071 {
1072 	UNI_TOKEN_LIST *ret;
1073 	UINT i;
1074 	// Validate arguments
1075 	if (src == NULL)
1076 	{
1077 		return NULL;
1078 	}
1079 
1080 	ret = ZeroMalloc(sizeof(TOKEN_LIST));
1081 	ret->NumTokens = src->NumTokens;
1082 	ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
1083 	for (i = 0;i < ret->NumTokens;i++)
1084 	{
1085 		ret->Token[i] = CopyUniStr(src->Token[i]);
1086 	}
1087 
1088 	return ret;
1089 }
1090 
1091 // Parse the command line string
UniParseCmdLine(wchar_t * str)1092 UNI_TOKEN_LIST *UniParseCmdLine(wchar_t *str)
1093 {
1094 	UNI_TOKEN_LIST *t;
1095 	LIST *o;
1096 	UINT i, len, wp, mode;
1097 	wchar_t c;
1098 	wchar_t *tmp;
1099 	bool ignore_space = false;
1100 	// Validate arguments
1101 	if (str == NULL)
1102 	{
1103 		// There is no token
1104 		return UniNullToken();
1105 	}
1106 
1107 	o = NewListFast(NULL);
1108 	tmp = Malloc(UniStrSize(str) + 32);
1109 
1110 	wp = 0;
1111 	mode = 0;
1112 
1113 	len = UniStrLen(str);
1114 	for (i = 0;i < len;i++)
1115 	{
1116 		c = str[i];
1117 
1118 		switch (mode)
1119 		{
1120 		case 0:
1121 			// Mode to discover the next token
1122 			if (c == L' ' || c == L'\t')
1123 			{
1124 				// Advance to the next character
1125 			}
1126 			else
1127 			{
1128 				// Start of the token
1129 				if (c == L'\"')
1130 				{
1131 					if (str[i + 1] == L'\"')
1132 					{
1133 						// Regarded "" as a single " character
1134 						tmp[wp++] = L'\"';
1135 						i++;
1136 					}
1137 					else
1138 					{
1139 						// Single "(double-quote) enables the flag to ignore space
1140 					ignore_space = true;
1141 					}
1142 				}
1143 				else
1144 				{
1145 					tmp[wp++] = c;
1146 				}
1147 
1148 				mode = 1;
1149 			}
1150 			break;
1151 
1152 		case 1:
1153 			if (ignore_space == false && (c == L' ' || c == L'\t'))
1154 			{
1155 				// End of the token
1156 				tmp[wp++] = 0;
1157 				wp = 0;
1158 
1159 				Insert(o, UniCopyStr(tmp));
1160 				mode = 0;
1161 			}
1162 			else
1163 			{
1164 				if (c == L'\"')
1165 				{
1166 					if (str[i + 1] == L'\"')
1167 					{
1168 						// Regarded "" as a single " character
1169 						tmp[wp++] = L'\"';
1170 						i++;
1171 					}
1172 					else
1173 					{
1174 						if (ignore_space == false)
1175 						{
1176 							// Single "(double-quote) enables the flag to ignore space
1177 							ignore_space = true;
1178 						}
1179 						else
1180 						{
1181 							// Disable the flag to ignore space
1182 							ignore_space = false;
1183 						}
1184 					}
1185 				}
1186 				else
1187 				{
1188 					tmp[wp++] = c;
1189 				}
1190 			}
1191 			break;
1192 		}
1193 	}
1194 
1195 	if (wp != 0)
1196 	{
1197 		tmp[wp++] = 0;
1198 		Insert(o, UniCopyStr(tmp));
1199 	}
1200 
1201 	Free(tmp);
1202 
1203 	t = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
1204 	t->NumTokens = LIST_NUM(o);
1205 	t->Token = ZeroMalloc(sizeof(wchar_t *) * t->NumTokens);
1206 	for (i = 0;i < t->NumTokens;i++)
1207 	{
1208 		t->Token[i] = LIST_DATA(o, i);
1209 	}
1210 
1211 	ReleaseList(o);
1212 
1213 	return t;
1214 }
1215 
1216 // Convert Unicode string to 64bit integer
UniToInt64(wchar_t * str)1217 UINT64 UniToInt64(wchar_t *str)
1218 {
1219 	char tmp[MAX_SIZE];
1220 	// Validate arguments
1221 	if (str == NULL)
1222 	{
1223 		return 0;
1224 	}
1225 
1226 	UniToStrForSingleChars(tmp, sizeof(tmp), str);
1227 
1228 	return ToInt64(tmp);
1229 }
1230 
1231 // Convert the UTF string to a Unicode string
UtfToUni(wchar_t * unistr,UINT size,char * utfstr)1232 UINT UtfToUni(wchar_t *unistr, UINT size, char *utfstr)
1233 {
1234 	wchar_t *tmp;
1235 	// Validate arguments
1236 	if (unistr == NULL || utfstr == NULL)
1237 	{
1238 		UniStrCpy(unistr, size, L"");
1239 		return 0;
1240 	}
1241 
1242 	tmp = CopyUtfToUni(utfstr);
1243 
1244 	UniStrCpy(unistr, size, tmp);
1245 
1246 	Free(tmp);
1247 
1248 	return UniStrLen(unistr);
1249 }
1250 
1251 // Copy the UTF-8 string to a Unicode string
CopyUtfToUni(char * utfstr)1252 wchar_t *CopyUtfToUni(char *utfstr)
1253 {
1254 	UINT size;
1255 	wchar_t *ret;
1256 	UINT utfstr_len;
1257 	// Validate arguments
1258 	if (utfstr == NULL)
1259 	{
1260 		return NULL;
1261 	}
1262 
1263 	utfstr_len = StrLen(utfstr);
1264 
1265 	size = CalcUtf8ToUni((BYTE *)utfstr, utfstr_len);
1266 	ret = ZeroMalloc(size + sizeof(wchar_t));
1267 	Utf8ToUni(ret, size, (BYTE *)utfstr, utfstr_len);
1268 
1269 	return ret;
1270 }
1271 
1272 // Copy a Unicode string to ANSI string
CopyUniToStr(wchar_t * unistr)1273 char *CopyUniToStr(wchar_t *unistr)
1274 {
1275 	char *str;
1276 	UINT str_size;
1277 	// Validate arguments
1278 	if (unistr == NULL)
1279 	{
1280 		return NULL;
1281 	}
1282 
1283 	str_size = CalcUniToStr(unistr);
1284 	if (str_size == 0)
1285 	{
1286 		return CopyStr("");
1287 	}
1288 	str = Malloc(str_size);
1289 	UniToStr(str, str_size, unistr);
1290 
1291 	return str;
1292 }
1293 
1294 // Copy an ANSI string to a Unicode string
CopyStrToUni(char * str)1295 wchar_t *CopyStrToUni(char *str)
1296 {
1297 	wchar_t *uni;
1298 	UINT uni_size;
1299 	// Validate arguments
1300 	if (str == NULL)
1301 	{
1302 		return NULL;
1303 	}
1304 
1305 	uni_size = CalcStrToUni(str);
1306 	if (uni_size == 0)
1307 	{
1308 		return CopyUniStr(L"");
1309 	}
1310 	uni = Malloc(uni_size);
1311 	StrToUni(uni, uni_size, str);
1312 
1313 	return uni;
1314 }
1315 
1316 // Copy a Unicode string to UTF-8 string
CopyUniToUtf(wchar_t * unistr)1317 char *CopyUniToUtf(wchar_t *unistr)
1318 {
1319 	UINT size;
1320 	char *ret;
1321 	// Validate arguments
1322 	if (unistr == NULL)
1323 	{
1324 		return NULL;
1325 	}
1326 
1327 	size = CalcUniToUtf8(unistr);
1328 	ret = ZeroMalloc(size + sizeof(char));
1329 
1330 	UniToUtf8((char *)ret, size, unistr);
1331 
1332 	return ret;
1333 }
1334 
1335 // Copy the Unicode string
CopyUniStr(wchar_t * str)1336 wchar_t *CopyUniStr(wchar_t *str)
1337 {
1338 	UINT len;
1339 	wchar_t *dst;
1340 	// Validate arguments
1341 	if (str == NULL)
1342 	{
1343 		return NULL;
1344 	}
1345 
1346 	len = UniStrLen(str);
1347 	dst = Malloc((len + 1) * sizeof(wchar_t));
1348 	UniStrCpy(dst, 0, str);
1349 
1350 	return dst;
1351 }
1352 
1353 // Check whether the string is safe
IsSafeUniStr(wchar_t * str)1354 bool IsSafeUniStr(wchar_t *str)
1355 {
1356 	UINT i, len;
1357 	// Validate arguments
1358 	if (str == NULL)
1359 	{
1360 		return false;
1361 	}
1362 
1363 	len = UniStrLen(str);
1364 	for (i = 0;i < len;i++)
1365 	{
1366 		if (IsSafeUniChar(str[i]) == false)
1367 		{
1368 			return false;
1369 		}
1370 	}
1371 	if (str[0] == L' ')
1372 	{
1373 		return false;
1374 	}
1375 	if (len != 0)
1376 	{
1377 		if (str[len - 1] == L' ')
1378 		{
1379 			return false;
1380 		}
1381 	}
1382 	return true;
1383 }
1384 
1385 // Check whether the character is safe
IsSafeUniChar(wchar_t c)1386 bool IsSafeUniChar(wchar_t c)
1387 {
1388 	UINT i, len;
1389 	wchar_t *check_str =
1390 		L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1391 		L"abcdefghijklmnopqrstuvwxyz"
1392 		L"0123456789"
1393 		L" ()-_#%&.";
1394 
1395 	len = UniStrLen(check_str);
1396 	for (i = 0;i < len;i++)
1397 	{
1398 		if (c == check_str[i])
1399 		{
1400 			return true;
1401 		}
1402 	}
1403 	return false;
1404 }
1405 
1406 // Convert Unicode string to ANSI string
UniToStr(char * str,UINT size,wchar_t * s)1407 UINT UniToStr(char *str, UINT size, wchar_t *s)
1408 {
1409 #ifdef	OS_WIN32
1410 	UINT ret;
1411 	char *tmp;
1412 	UINT new_size;
1413 	// Validate arguments
1414 	if (s == NULL || str == NULL)
1415 	{
1416 		return 0;
1417 	}
1418 
1419 	new_size = CalcUniToStr(s);
1420 	if (new_size == 0)
1421 	{
1422 		if (size >= 1)
1423 		{
1424 			StrCpy(str, 0, "");
1425 		}
1426 		return 0;
1427 	}
1428 	tmp = Malloc(new_size);
1429 	tmp[0] = 0;
1430 	wcstombs(tmp, s, new_size);
1431 	tmp[new_size - 1] = 0;
1432 	ret = StrCpy(str, size, tmp);
1433 	Free(tmp);
1434 
1435 	return ret;
1436 #else	// OS_WIN32
1437 	return UnixUniToStr(str, size, s);
1438 #endif	// OS_WIN32
1439 }
1440 
1441 // Get the required number of bytes to convert Unicode string to the ANSI string
CalcUniToStr(wchar_t * s)1442 UINT CalcUniToStr(wchar_t *s)
1443 {
1444 #ifdef	OS_WIN32
1445 	UINT ret;
1446 	// Validate arguments
1447 	if (s == NULL)
1448 	{
1449 		return 0;
1450 	}
1451 
1452 	ret = (UINT)wcstombs(NULL, s, UniStrLen(s));
1453 	if (ret == (UINT)-1)
1454 	{
1455 		return 0;
1456 	}
1457 
1458 	return ret + 1;
1459 #else	// OS_WIN32
1460 	return UnixCalcUniToStr(s);
1461 #endif	// OS_WIN32
1462 }
1463 
1464 // Converted an ANSI string to a Unicode string
StrToUni(wchar_t * s,UINT size,char * str)1465 UINT StrToUni(wchar_t *s, UINT size, char *str)
1466 {
1467 #ifdef	OS_WIN32
1468 	UINT ret;
1469 	wchar_t *tmp;
1470 	UINT new_size;
1471 	// Validate arguments
1472 	if (s == NULL || str == NULL)
1473 	{
1474 		return 0;
1475 	}
1476 
1477 	new_size = CalcStrToUni(str);
1478 	if (new_size == 0)
1479 	{
1480 		if (size >= 2)
1481 		{
1482 			UniStrCpy(s, 0, L"");
1483 		}
1484 		return 0;
1485 	}
1486 	tmp = Malloc(new_size);
1487 	tmp[0] = 0;
1488 	mbstowcs(tmp, str, StrLen(str));
1489 	tmp[(new_size - 1) / sizeof(wchar_t)] = 0;
1490 	ret = UniStrCpy(s, size, tmp);
1491 	Free(tmp);
1492 
1493 	return ret;
1494 #else	// OS_WIN32
1495 	return UnixStrToUni(s, size, str);
1496 #endif	// OS_WIN32
1497 }
1498 
1499 // Get the required buffer size for converting an ANSI string to an Unicode string
CalcStrToUni(char * str)1500 UINT CalcStrToUni(char *str)
1501 {
1502 #ifdef	OS_WIN32
1503 	UINT ret;
1504 	// Validate arguments
1505 	if (str == NULL)
1506 	{
1507 		return 0;
1508 	}
1509 
1510 	ret = (UINT)mbstowcs(NULL, str, StrLen(str));
1511 	if (ret == (UINT)-1)
1512 	{
1513 		return 0;
1514 	}
1515 
1516 	return (ret + 1) * sizeof(wchar_t);
1517 #else	// OS_WIN32
1518 	return UnixCalcStrToUni(str);
1519 #endif	// OS_WIN32
1520 }
1521 
1522 // Convert the UTF-8 strings to a Unicode string
Utf8ToUni(wchar_t * s,UINT size,BYTE * u,UINT u_size)1523 UINT Utf8ToUni(wchar_t *s, UINT size, BYTE *u, UINT u_size)
1524 {
1525 	UINT i, wp, num;
1526 	// Validate arguments
1527 	if (s == NULL || u == NULL)
1528 	{
1529 		return 0;
1530 	}
1531 	if (size == 0)
1532 	{
1533 		size = 0x3fffffff;
1534 	}
1535 	if (u_size == 0)
1536 	{
1537 		u_size = StrLen((char *)u);
1538 	}
1539 
1540 	i = 0;
1541 	wp = 0;
1542 	num = 0;
1543 	while (true)
1544 	{
1545 		UINT type;
1546 		wchar_t c = 0;
1547 		BYTE c1, c2;
1548 
1549 		type = GetUtf8Type(u, u_size, i);
1550 		if (type == 0)
1551 		{
1552 			break;
1553 		}
1554 		switch (type)
1555 		{
1556 		case 1:
1557 			c1 = 0;
1558 			c2 = u[i];
1559 			break;
1560 		case 2:
1561 			c1 = (((u[i] & 0x1c) >> 2) & 0x07);
1562 			c2 = (((u[i] & 0x03) << 6) & 0xc0) | (u[i + 1] & 0x3f);
1563 			break;
1564 		case 3:
1565 			c1 = ((((u[i] & 0x0f) << 4) & 0xf0)) | (((u[i + 1] & 0x3c) >> 2) & 0x0f);
1566 			c2 = (((u[i + 1] & 0x03) << 6) & 0xc0) | (u[i + 2] & 0x3f);
1567 			break;
1568 		}
1569 		i += type;
1570 
1571 		if (IsBigEndian())
1572 		{
1573 			if (sizeof(wchar_t) == 2)
1574 			{
1575 				((BYTE *)&c)[0] = c1;
1576 				((BYTE *)&c)[1] = c2;
1577 			}
1578 			else
1579 			{
1580 				((BYTE *)&c)[2] = c1;
1581 				((BYTE *)&c)[3] = c2;
1582 			}
1583 		}
1584 		else
1585 		{
1586 			((BYTE *)&c)[0] = c2;
1587 			((BYTE *)&c)[1] = c1;
1588 		}
1589 
1590 		if (wp < ((size / sizeof(wchar_t)) - 1))
1591 		{
1592 			s[wp++] = c;
1593 			num++;
1594 		}
1595 		else
1596 		{
1597 			break;
1598 		}
1599 	}
1600 
1601 	if (wp < (size / sizeof(wchar_t)))
1602 	{
1603 		s[wp++] = 0;
1604 	}
1605 
1606 	return num;
1607 }
1608 
1609 // Get the buffer size when converted UTF-8 to Unicode
CalcUtf8ToUni(BYTE * u,UINT u_size)1610 UINT CalcUtf8ToUni(BYTE *u, UINT u_size)
1611 {
1612 	// Validate arguments
1613 	if (u == NULL)
1614 	{
1615 		return 0;
1616 	}
1617 	if (u_size == 0)
1618 	{
1619 		u_size = StrLen((char *)u);
1620 	}
1621 
1622 	return (Utf8Len(u, u_size) + 1) * sizeof(wchar_t);
1623 }
1624 
1625 // Get the number of characters in UTF-8 string
Utf8Len(BYTE * u,UINT size)1626 UINT Utf8Len(BYTE *u, UINT size)
1627 {
1628 	UINT i, num;
1629 	// Validate arguments
1630 	if (u == NULL)
1631 	{
1632 		return 0;
1633 	}
1634 	if (size == 0)
1635 	{
1636 		size = StrLen((char *)u);
1637 	}
1638 
1639 	i = num = 0;
1640 	while (true)
1641 	{
1642 		UINT type;
1643 
1644 		type = GetUtf8Type(u, size, i);
1645 		if (type == 0)
1646 		{
1647 			break;
1648 		}
1649 		i += type;
1650 		num++;
1651 	}
1652 
1653 	return num;
1654 }
1655 
1656 // Convert an Unicode string to UTF-8 string
UniToUtf8(BYTE * u,UINT size,wchar_t * s)1657 UINT UniToUtf8(BYTE *u, UINT size, wchar_t *s)
1658 {
1659 	UINT i, len, type, wp;
1660 	// Validate arguments
1661 	if (u == NULL || s == NULL)
1662 	{
1663 		return 0;
1664 	}
1665 	if (size == 0)
1666 	{
1667 		size = 0x3fffffff;
1668 	}
1669 
1670 	len = UniStrLen(s);
1671 	wp = 0;
1672 	for (i = 0;i < len;i++)
1673 	{
1674 		BYTE c1, c2;
1675 		wchar_t c = s[i];
1676 
1677 		if (IsBigEndian())
1678 		{
1679 			if (sizeof(wchar_t) == 2)
1680 			{
1681 				c1 = ((BYTE *)&c)[0];
1682 				c2 = ((BYTE *)&c)[1];
1683 			}
1684 			else
1685 			{
1686 				c1 = ((BYTE *)&c)[2];
1687 				c2 = ((BYTE *)&c)[3];
1688 			}
1689 		}
1690 		else
1691 		{
1692 			c1 = ((BYTE *)&c)[1];
1693 			c2 = ((BYTE *)&c)[0];
1694 		}
1695 
1696 		type = GetUniType(s[i]);
1697 		switch (type)
1698 		{
1699 		case 1:
1700 			if (wp < size)
1701 			{
1702 				u[wp++] = c2;
1703 			}
1704 			break;
1705 		case 2:
1706 			if (wp < size)
1707 			{
1708 				u[wp++] = 0xc0 | (((((c1 & 0x07) << 2) & 0x1c)) | (((c2 & 0xc0) >> 6) & 0x03));
1709 			}
1710 			if (wp < size)
1711 			{
1712 				u[wp++] = 0x80 | (c2 & 0x3f);
1713 			}
1714 			break;
1715 		case 3:
1716 			if (wp < size)
1717 			{
1718 				u[wp++] = 0xe0 | (((c1 & 0xf0) >> 4) & 0x0f);
1719 			}
1720 			if (wp < size)
1721 			{
1722 				u[wp++] = 0x80 | (((c1 & 0x0f) << 2) & 0x3c) | (((c2 & 0xc0) >> 6) & 0x03);
1723 			}
1724 			if (wp < size)
1725 			{
1726 				u[wp++] = 0x80 | (c2 & 0x3f);
1727 			}
1728 			break;
1729 		}
1730 	}
1731 	if (wp < size)
1732 	{
1733 		u[wp] = 0;
1734 	}
1735 	return wp;
1736 }
1737 
1738 // Calculating the length of the string when converting Unicode string to UTF-8 string
CalcUniToUtf8(wchar_t * s)1739 UINT CalcUniToUtf8(wchar_t *s)
1740 {
1741 	UINT i, len, size;
1742 	// Validate arguments
1743 	if (s == NULL)
1744 	{
1745 		return 0;
1746 	}
1747 
1748 	size = 0;
1749 	len = UniStrLen(s);
1750 	for (i = 0;i < len;i++)
1751 	{
1752 		size += GetUniType(s[i]);
1753 	}
1754 
1755 	return size;
1756 }
1757 
1758 // Get the number of bytes of a first character of the offset address of the UTF-8 string that starts with s
GetUtf8Type(BYTE * s,UINT size,UINT offset)1759 UINT GetUtf8Type(BYTE *s, UINT size, UINT offset)
1760 {
1761 	// Validate arguments
1762 	if (s == NULL)
1763 	{
1764 		return 0;
1765 	}
1766 	if ((offset + 1) > size)
1767 	{
1768 		return 0;
1769 	}
1770 	if ((s[offset] & 0x80) == 0)
1771 	{
1772 		// 1 byte
1773 		return 1;
1774 	}
1775 	if ((s[offset] & 0x20) == 0)
1776 	{
1777 		// 2 bytes
1778 		if ((offset + 2) > size)
1779 		{
1780 			return 0;
1781 		}
1782 		return 2;
1783 	}
1784 	// 3 bytes
1785 	if ((offset + 3) > size)
1786 	{
1787 		return 0;
1788 	}
1789 	return 3;
1790 }
1791 
1792 // Type of the converted character 'c' to UTF-8 (in bytes)
GetUniType(wchar_t c)1793 UINT GetUniType(wchar_t c)
1794 {
1795 	BYTE c1, c2;
1796 
1797 	if (IsBigEndian())
1798 	{
1799 		if (sizeof(wchar_t) == 2)
1800 		{
1801 			c1 = ((BYTE *)&c)[0];
1802 			c2 = ((BYTE *)&c)[1];
1803 		}
1804 		else
1805 		{
1806 			c1 = ((BYTE *)&c)[2];
1807 			c2 = ((BYTE *)&c)[3];
1808 		}
1809 	}
1810 	else
1811 	{
1812 		c1 = ((BYTE *)&c)[1];
1813 		c2 = ((BYTE *)&c)[0];
1814 	}
1815 
1816 	if (c1 == 0)
1817 	{
1818 		if (c2 <= 0x7f)
1819 		{
1820 			// 1 byte
1821 			return 1;
1822 		}
1823 		else
1824 		{
1825 			// 2 bytes
1826 			return 2;
1827 		}
1828 	}
1829 	if ((c1 & 0xf8) == 0)
1830 	{
1831 		// 2 bytes
1832 		return 2;
1833 	}
1834 	// 3 bytes
1835 	return 3;
1836 }
1837 
1838 // String replacing (case-sensitive)
UniReplaceStr(wchar_t * dst,UINT size,wchar_t * string,wchar_t * old_keyword,wchar_t * new_keyword)1839 UINT UniReplaceStr(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword)
1840 {
1841 	return UniReplaceStrEx(dst, size, string, old_keyword, new_keyword, true);
1842 }
1843 
1844 // Replacement of string
UniReplaceStrEx(wchar_t * dst,UINT size,wchar_t * string,wchar_t * old_keyword,wchar_t * new_keyword,bool case_sensitive)1845 UINT UniReplaceStrEx(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword, bool case_sensitive)
1846 {
1847 	UINT i, j, num, len_string, len_old, len_new, len_ret, wp;
1848 	wchar_t *ret;
1849 	// Validate arguments
1850 	if (string == NULL || old_keyword == NULL || new_keyword == NULL)
1851 	{
1852 		return 0;
1853 	}
1854 
1855 	// Get the length of the string
1856 	len_string = UniStrLen(string);
1857 	len_old = UniStrLen(old_keyword);
1858 	len_new = UniStrLen(new_keyword);
1859 
1860 	// Get the final string length
1861 	len_ret = UniCalcReplaceStrEx(string, old_keyword, new_keyword, case_sensitive);
1862 	// Memory allocation
1863 	ret = Malloc((len_ret + 1) * sizeof(wchar_t));
1864 	ret[len_ret] = 0;
1865 
1866 	// Search and Replace
1867 	i = j = num = wp = 0;
1868 	while (true)
1869 	{
1870 		i = UniSearchStrEx(string, old_keyword, i, case_sensitive);
1871 		if (i == INFINITE)
1872 		{
1873 			Copy(&ret[wp], &string[j], (len_string - j) * sizeof(wchar_t));
1874 			wp += len_string - j;
1875 			break;
1876 		}
1877 		num++;
1878 		Copy(&ret[wp], &string[j], (i - j) * sizeof(wchar_t));
1879 		wp += i - j;
1880 		Copy(&ret[wp], new_keyword, len_new * sizeof(wchar_t));
1881 		wp += len_new;
1882 		i += len_old;
1883 		j = i;
1884 	}
1885 
1886 	// Copy of the search results
1887 	UniStrCpy(dst, size, ret);
1888 
1889 	// Memory release
1890 	Free(ret);
1891 
1892 	return num;
1893 }
1894 
1895 // Calculate the length of the result of string replacement
UniCalcReplaceStrEx(wchar_t * string,wchar_t * old_keyword,wchar_t * new_keyword,bool case_sensitive)1896 UINT UniCalcReplaceStrEx(wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword, bool case_sensitive)
1897 {
1898 	UINT i, num;
1899 	UINT len_string, len_old, len_new;
1900 	// Validate arguments
1901 	if (string == NULL || old_keyword == NULL || new_keyword == NULL)
1902 	{
1903 		return 0;
1904 	}
1905 
1906 	// Get the length of the string
1907 	len_string = UniStrLen(string);
1908 	len_old = UniStrLen(old_keyword);
1909 	len_new = UniStrLen(new_keyword);
1910 
1911 	if (len_old == len_new)
1912 	{
1913 		return len_string;
1914 	}
1915 
1916 	// Search process
1917 	num = 0;
1918 	i = 0;
1919 	while (true)
1920 	{
1921 		i = UniSearchStrEx(string, old_keyword, i, case_sensitive);
1922 		if (i == INFINITE)
1923 		{
1924 			break;
1925 		}
1926 		i += len_old;
1927 		num++;
1928 	}
1929 
1930 	// Calculation
1931 	return len_string + len_new * num - len_old * num;
1932 }
1933 
1934 // Search for a string (distinguish between upper / lower case)
UniSearchStr(wchar_t * string,wchar_t * keyword,UINT start)1935 UINT UniSearchStr(wchar_t *string, wchar_t *keyword, UINT start)
1936 {
1937 	return UniSearchStrEx(string, keyword, start, true);
1938 }
1939 
1940 // Return the position of the first found of the keyword in the string
1941 // (Found in first character: returns 0, Not found: returns INFINITE)
UniSearchStrEx(wchar_t * string,wchar_t * keyword,UINT start,bool case_sensitive)1942 UINT UniSearchStrEx(wchar_t *string, wchar_t *keyword, UINT start, bool case_sensitive)
1943 {
1944 	UINT len_string, len_keyword;
1945 	UINT i;
1946 	wchar_t *cmp_string, *cmp_keyword;
1947 	bool found;
1948 	// Validate arguments
1949 	if (string == NULL || keyword == NULL)
1950 	{
1951 		return INFINITE;
1952 	}
1953 
1954 	// Get the length of string
1955 	len_string = UniStrLen(string);
1956 	if (len_string <= start)
1957 	{
1958 		// Value of start is invalid
1959 		return INFINITE;
1960 	}
1961 
1962 	// Get the length of the keyword
1963 	len_keyword = UniStrLen(keyword);
1964 	if (len_keyword == 0)
1965 	{
1966 		// There is no keyword
1967 		return INFINITE;
1968 	}
1969 
1970 	if (len_string < len_keyword)
1971 	{
1972 		return INFINITE;
1973 	}
1974 
1975 	if (len_string == len_keyword)
1976 	{
1977 		if (case_sensitive)
1978 		{
1979 			if (UniStrCmp(string, keyword) == 0)
1980 			{
1981 				return 0;
1982 			}
1983 			else
1984 			{
1985 				return INFINITE;
1986 			}
1987 		}
1988 		else
1989 		{
1990 			if (UniStrCmpi(string, keyword) == 0)
1991 			{
1992 				return 0;
1993 			}
1994 			else
1995 			{
1996 				return INFINITE;
1997 			}
1998 		}
1999 	}
2000 
2001 	if (case_sensitive)
2002 	{
2003 		cmp_string = string;
2004 		cmp_keyword = keyword;
2005 	}
2006 	else
2007 	{
2008 		cmp_string = Malloc((len_string + 1) * sizeof(wchar_t));
2009 		UniStrCpy(cmp_string, (len_string + 1) * sizeof(wchar_t), string);
2010 		cmp_keyword = Malloc((len_keyword + 1) * sizeof(wchar_t));
2011 		UniStrCpy(cmp_keyword, (len_keyword + 1) * sizeof(wchar_t), keyword);
2012 		UniStrUpper(cmp_string);
2013 		UniStrUpper(cmp_keyword);
2014 	}
2015 
2016 	// Search
2017 	found = false;
2018 	for (i = start;i < (len_string - len_keyword + 1);i++)
2019 	{
2020 		// Compare
2021 		if (!wcsncmp(&cmp_string[i], cmp_keyword, len_keyword))
2022 		{
2023 			// Found
2024 			found = true;
2025 			break;
2026 		}
2027 	}
2028 
2029 	if (case_sensitive == false)
2030 	{
2031 		// Memory release
2032 		Free(cmp_keyword);
2033 		Free(cmp_string);
2034 	}
2035 
2036 	if (found == false)
2037 	{
2038 		return INFINITE;
2039 	}
2040 	return i;
2041 }
2042 
2043 // Release of the token list
UniFreeToken(UNI_TOKEN_LIST * tokens)2044 void UniFreeToken(UNI_TOKEN_LIST *tokens)
2045 {
2046 	UINT i;
2047 	if (tokens == NULL)
2048 	{
2049 		return;
2050 	}
2051 	for (i = 0;i < tokens->NumTokens;i++)
2052 	{
2053 		Free(tokens->Token[i]);
2054 	}
2055 	Free(tokens->Token);
2056 	Free(tokens);
2057 }
2058 
2059 // Parse token for UNIX
UnixUniParseToken(wchar_t * src,wchar_t * separator)2060 UNI_TOKEN_LIST *UnixUniParseToken(wchar_t *src, wchar_t *separator)
2061 {
2062 	UNI_TOKEN_LIST *ret;
2063 	TOKEN_LIST *t;
2064 	char *src_s;
2065 	char *sep_s;
2066 
2067 	// Validate arguments
2068 	if (src == NULL || separator == NULL)
2069 	{
2070 		ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
2071 		ret->Token = ZeroMalloc(0);
2072 		return ret;
2073 	}
2074 
2075 	src_s = CopyUniToStr(src);
2076 	sep_s = CopyUniToStr(separator);
2077 
2078 	t = ParseToken(src_s, sep_s);
2079 
2080 	ret = TokenListToUniTokenList(t);
2081 	FreeToken(t);
2082 
2083 	Free(src_s);
2084 	Free(sep_s);
2085 
2086 	return ret;
2087 }
2088 
2089 // Get a standard token delimiter
UniDefaultTokenSplitChars()2090 wchar_t *UniDefaultTokenSplitChars()
2091 {
2092 	return L" ,\t\r\n";
2093 }
2094 
2095 // Check whether the specified character is in the string
UniIsCharInStr(wchar_t * str,wchar_t c)2096 bool UniIsCharInStr(wchar_t *str, wchar_t c)
2097 {
2098 	UINT i, len;
2099 	// Validate arguments
2100 	if (str == NULL)
2101 	{
2102 		return false;
2103 	}
2104 
2105 	len = UniStrLen(str);
2106 	for (i = 0;i < len;i++)
2107 	{
2108 		if (str[i] == c)
2109 		{
2110 			return true;
2111 		}
2112 	}
2113 
2114 	return false;
2115 }
2116 
2117 // Cut out the token from the string (not ignore the blanks between delimiters)
UniParseTokenWithNullStr(wchar_t * str,wchar_t * split_chars)2118 UNI_TOKEN_LIST *UniParseTokenWithNullStr(wchar_t *str, wchar_t *split_chars)
2119 {
2120 	LIST *o;
2121 	UINT i, len;
2122 	BUF *b;
2123 	wchar_t zero = 0;
2124 	UNI_TOKEN_LIST *t;
2125 	// Validate arguments
2126 	if (str == NULL)
2127 	{
2128 		return UniNullToken();
2129 	}
2130 	if (split_chars == NULL)
2131 	{
2132 		split_chars = UniDefaultTokenSplitChars();
2133 	}
2134 
2135 	b = NewBuf();
2136 	o = NewListFast(NULL);
2137 
2138 	len = UniStrLen(str);
2139 
2140 	for (i = 0;i < (len + 1);i++)
2141 	{
2142 		wchar_t c = str[i];
2143 		bool flag = UniIsCharInStr(split_chars, c);
2144 
2145 		if (c == L'\0')
2146 		{
2147 			flag = true;
2148 		}
2149 
2150 		if (flag == false)
2151 		{
2152 			WriteBuf(b, &c, sizeof(wchar_t));
2153 		}
2154 		else
2155 		{
2156 			WriteBuf(b, &zero, sizeof(wchar_t));
2157 
2158 			Insert(o, UniCopyStr((wchar_t *)b->Buf));
2159 			ClearBuf(b);
2160 		}
2161 	}
2162 
2163 	t = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
2164 	t->NumTokens = LIST_NUM(o);
2165 	t->Token = ZeroMalloc(sizeof(wchar_t *) * t->NumTokens);
2166 
2167 	for (i = 0;i < t->NumTokens;i++)
2168 	{
2169 		t->Token[i] = LIST_DATA(o, i);
2170 	}
2171 
2172 	ReleaseList(o);
2173 	FreeBuf(b);
2174 
2175 	return t;
2176 }
2177 
2178 // Cut out the token from string (Ignore blanks between delimiters)
UniParseTokenWithoutNullStr(wchar_t * str,wchar_t * split_chars)2179 UNI_TOKEN_LIST *UniParseTokenWithoutNullStr(wchar_t *str, wchar_t *split_chars)
2180 {
2181 	LIST *o;
2182 	UINT i, len;
2183 	bool last_flag;
2184 	BUF *b;
2185 	wchar_t zero = 0;
2186 	UNI_TOKEN_LIST *t;
2187 	// Validate arguments
2188 	if (str == NULL)
2189 	{
2190 		return UniNullToken();
2191 	}
2192 	if (split_chars == NULL)
2193 	{
2194 		split_chars = UniDefaultTokenSplitChars();
2195 	}
2196 
2197 	b = NewBuf();
2198 	o = NewListFast(NULL);
2199 
2200 	len = UniStrLen(str);
2201 	last_flag = false;
2202 
2203 	for (i = 0;i < (len + 1);i++)
2204 	{
2205 		wchar_t c = str[i];
2206 		bool flag = UniIsCharInStr(split_chars, c);
2207 
2208 		if (c == L'\0')
2209 		{
2210 			flag = true;
2211 		}
2212 
2213 		if (flag == false)
2214 		{
2215 			WriteBuf(b, &c, sizeof(wchar_t));
2216 		}
2217 		else
2218 		{
2219 			if (last_flag == false)
2220 			{
2221 				WriteBuf(b, &zero, sizeof(wchar_t));
2222 
2223 				if ((UniStrLen((wchar_t *)b->Buf)) != 0)
2224 				{
2225 					Insert(o, UniCopyStr((wchar_t *)b->Buf));
2226 				}
2227 				ClearBuf(b);
2228 			}
2229 		}
2230 
2231 		last_flag = flag;
2232 	}
2233 
2234 	t = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
2235 	t->NumTokens = LIST_NUM(o);
2236 	t->Token = ZeroMalloc(sizeof(wchar_t *) * t->NumTokens);
2237 
2238 	for (i = 0;i < t->NumTokens;i++)
2239 	{
2240 		t->Token[i] = LIST_DATA(o, i);
2241 	}
2242 
2243 	ReleaseList(o);
2244 	FreeBuf(b);
2245 
2246 	return t;
2247 }
2248 
2249 // Parse the token
UniParseToken(wchar_t * src,wchar_t * separator)2250 UNI_TOKEN_LIST *UniParseToken(wchar_t *src, wchar_t *separator)
2251 {
2252 	// 2020/7/20 remove strtok by dnobori
2253 	return UniParseTokenWithoutNullStr(src, separator);
2254 }
2255 
2256 // Get a line from standard input
UniGetLine(wchar_t * str,UINT size)2257 bool UniGetLine(wchar_t *str, UINT size)
2258 {
2259 #ifdef	OS_WIN32
2260 	return UniGetLineWin32(str, size);
2261 #else	// OS_WIN32
2262 	return UniGetLineUnix(str, size);
2263 #endif	// OS_WIN32
2264 }
AnsiGetLineUnix(char * str,UINT size)2265 void AnsiGetLineUnix(char *str, UINT size)
2266 {
2267 	// Validate arguments
2268 	if (str == NULL)
2269 	{
2270 		char tmp[MAX_SIZE];
2271 		fgets(tmp, sizeof(tmp) - 1, stdin);
2272 		return;
2273 	}
2274 	if (size <= 1)
2275 	{
2276 		return;
2277 	}
2278 
2279 	// Read data from standard input
2280 	fgets(str, (int)(size - 1), stdin);
2281 
2282 	TrimCrlf(str);
2283 }
UniGetLineUnix(wchar_t * str,UINT size)2284 bool UniGetLineUnix(wchar_t *str, UINT size)
2285 {
2286 	char *str_a;
2287 	UINT str_a_size = size;
2288 	if (str == NULL || size < sizeof(wchar_t))
2289 	{
2290 		return false;
2291 	}
2292 	if (str_a_size >= 0x7fffffff)
2293 	{
2294 		str_a_size = MAX_SIZE;
2295 	}
2296 	str_a_size *= 2;
2297 
2298 	str_a = ZeroMalloc(str_a_size);
2299 
2300 	AnsiGetLineUnix(str_a, str_a_size);
2301 
2302 	StrToUni(str, size, str_a);
2303 
2304 	Free(str_a);
2305 
2306 	return true;
2307 }
UniGetLineWin32(wchar_t * str,UINT size)2308 bool UniGetLineWin32(wchar_t *str, UINT size)
2309 {
2310 	bool ret = false;
2311 
2312 #ifdef	OS_WIN32
2313 	ret = Win32InputW(str, size);
2314 #endif	// OS_WIN32
2315 
2316 	return ret;
2317 }
2318 
2319 // Remove '\r\n' at the end
UniTrimCrlf(wchar_t * str)2320 void UniTrimCrlf(wchar_t *str)
2321 {
2322 	UINT len;
2323 	// Validate arguments
2324 	if (str == NULL)
2325 	{
2326 		return;
2327 	}
2328 	len = UniStrLen(str);
2329 	if (len == 0)
2330 	{
2331 		return;
2332 	}
2333 
2334 	if (str[len - 1] == L'\n')
2335 	{
2336 		if (len >= 2 && str[len - 2] == L'\r')
2337 		{
2338 			str[len - 2] = 0;
2339 		}
2340 		str[len - 1] = 0;
2341 	}
2342 	else if(str[len - 1] == L'\r')
2343 	{
2344 		str[len - 1] = 0;
2345 	}
2346 }
2347 
2348 // Remove white space of the both side of the string
UniTrim(wchar_t * str)2349 void UniTrim(wchar_t *str)
2350 {
2351 	// Validate arguments
2352 	if (str == NULL)
2353 	{
2354 		return;
2355 	}
2356 
2357 	UniTrimLeft(str);
2358 	UniTrimRight(str);
2359 }
2360 
2361 // Remove white space on the right side of the string
UniTrimRight(wchar_t * str)2362 void UniTrimRight(wchar_t *str)
2363 {
2364 	wchar_t *buf, *tmp;
2365 	UINT len, i, wp, wp2;
2366 	bool flag;
2367 	// Validate arguments
2368 	if (str == NULL)
2369 	{
2370 		return;
2371 	}
2372 	len = UniStrLen(str);
2373 	if (len == 0)
2374 	{
2375 		return;
2376 	}
2377 	if (str[len - 1] != L' ' && str[len - 1] != L'\t')
2378 	{
2379 		return;
2380 	}
2381 
2382 	buf = Malloc((len + 1) * sizeof(wchar_t));
2383 	tmp = Malloc((len + 1) * sizeof(wchar_t));
2384 	flag = false;
2385 	wp = wp2 = 0;
2386 	for (i = 0;i < len;i++)
2387 	{
2388 		if (str[i] != L' ' && str[i] != L'\t')
2389 		{
2390 			Copy(&buf[wp], tmp, wp2 * sizeof(wchar_t));
2391 			wp += wp2;
2392 			wp2 = 0;
2393 			buf[wp++] = str[i];
2394 		}
2395 		else
2396 		{
2397 			tmp[wp2++] = str[i];
2398 		}
2399 	}
2400 	buf[wp] = 0;
2401 	UniStrCpy(str, 0, buf);
2402 	Free(buf);
2403 	Free(tmp);
2404 }
2405 
2406 // Remove white space from the left side of the string
UniTrimLeft(wchar_t * str)2407 void UniTrimLeft(wchar_t *str)
2408 {
2409 	wchar_t *buf;
2410 	UINT len, i, wp;
2411 	bool flag;
2412 	// Validate arguments
2413 	if (str == NULL)
2414 	{
2415 		return;
2416 	}
2417 	len = UniStrLen(str);
2418 	if (len == 0)
2419 	{
2420 		return;
2421 	}
2422 	if (str[0] != L' ' && str[0] != L'\t')
2423 	{
2424 		return;
2425 	}
2426 
2427 	buf = Malloc((len + 1) * sizeof(wchar_t));
2428 	flag = false;
2429 	wp = 0;
2430 	for (i = 0;i < len;i++)
2431 	{
2432 		if (str[i] != L' ' && str[i] != L'\t')
2433 		{
2434 			flag = true;
2435 		}
2436 		if (flag)
2437 		{
2438 			buf[wp++] = str[i];
2439 		}
2440 	}
2441 	buf[wp] = 0;
2442 	UniStrCpy(str, 0, buf);
2443 	Free(buf);
2444 }
2445 
2446 // Convert a signed integer to a string
UniToStri(wchar_t * str,int i)2447 void UniToStri(wchar_t *str, int i)
2448 {
2449 	UniFormat(str, 0, L"%i", i);
2450 }
2451 
2452 // Convert an integer to a string
UniToStru(wchar_t * str,UINT i)2453 void UniToStru(wchar_t *str, UINT i)
2454 {
2455 	UniFormat(str, 0, L"%u", i);
2456 }
2457 
2458 // Convert a string to an integer
UniToInt(wchar_t * str)2459 UINT UniToInt(wchar_t *str)
2460 {
2461 	char tmp[128];
2462 	// Validate arguments
2463 	if (str == NULL)
2464 	{
2465 		return 0;
2466 	}
2467 
2468 	UniToStrForSingleChars(tmp, sizeof(tmp), str);
2469 
2470 	return ToInti(tmp);
2471 }
2472 
2473 // Convert only single-byte characters in the Unicode string to a char string
UniToStrForSingleChars(char * dst,UINT dst_size,wchar_t * src)2474 void UniToStrForSingleChars(char *dst, UINT dst_size, wchar_t *src)
2475 {
2476 	UINT i;
2477 	// Validate arguments
2478 	if (dst == NULL || src == NULL)
2479 	{
2480 		return;
2481 	}
2482 
2483 	for (i = 0;i < UniStrLen(src) + 1;i++)
2484 	{
2485 		wchar_t s = src[i];
2486 		char d;
2487 
2488 		if (s == 0)
2489 		{
2490 			d = 0;
2491 		}
2492 		else if (s <= 0xff)
2493 		{
2494 			d = (char)s;
2495 		}
2496 		else
2497 		{
2498 			d = ' ';
2499 		}
2500 
2501 		dst[i] = d;
2502 	}
2503 }
2504 
2505 // Get lines from a string
UniGetLines(wchar_t * str)2506 UNI_TOKEN_LIST *UniGetLines(wchar_t *str)
2507 {
2508 	UINT i, len;
2509 	BUF *b = NULL;
2510 	LIST *o;
2511 	UNI_TOKEN_LIST *ret;
2512 	// Validate arguments
2513 	if (str == NULL)
2514 	{
2515 		return UniNullToken();
2516 	}
2517 
2518 	o = NewListFast(NULL);
2519 
2520 	len = UniStrLen(str);
2521 
2522 	b = NewBuf();
2523 
2524 	for (i = 0;i < len;i++)
2525 	{
2526 		wchar_t c = str[i];
2527 		bool f = false;
2528 
2529 		if (c == L'\r')
2530 		{
2531 			if (str[i + 1] == L'\n')
2532 			{
2533 				i++;
2534 			}
2535 			f = true;
2536 		}
2537 		else if (c == L'\n')
2538 		{
2539 			f = true;
2540 		}
2541 
2542 		if (f)
2543 		{
2544 			wchar_t zero = 0;
2545 			wchar_t *s;
2546 			WriteBuf(b, &zero, sizeof(wchar_t));
2547 
2548 			s = (wchar_t *)b->Buf;
2549 
2550 			Add(o, UniCopyStr(s));
2551 
2552 			ClearBuf(b);
2553 		}
2554 		else
2555 		{
2556 			WriteBuf(b, &c, sizeof(wchar_t));
2557 		}
2558 	}
2559 
2560 	if (true)
2561 	{
2562 		wchar_t zero = 0;
2563 		wchar_t *s;
2564 		WriteBuf(b, &zero, sizeof(wchar_t));
2565 
2566 		s = (wchar_t *)b->Buf;
2567 
2568 		Add(o, UniCopyStr(s));
2569 
2570 		ClearBuf(b);
2571 	}
2572 
2573 	FreeBuf(b);
2574 
2575 	ret = UniListToTokenList(o);
2576 
2577 	UniFreeStrList(o);
2578 
2579 	return ret;
2580 }
2581 
2582 // Display the string on the screen
UniPrintStr(wchar_t * string)2583 void UniPrintStr(wchar_t *string)
2584 {
2585 	// Validate arguments
2586 	if (string == NULL)
2587 	{
2588 		return;
2589 	}
2590 
2591 #ifdef	OS_UNIX
2592 	if (true)
2593 	{
2594 		char *str = CopyUniToStr(string);
2595 
2596 		if (str != NULL)
2597 		{
2598 			fputs(str, stdout);
2599 		}
2600 		else
2601 		{
2602 			fputs("", stdout);
2603 		}
2604 
2605 		Free(str);
2606 	}
2607 #else	// OS_UNIX
2608 	Win32PrintW(string);
2609 #endif	// OS_UNIX
2610 }
2611 
2612 // Display a string with arguments
UniPrintArgs(wchar_t * fmt,va_list args)2613 void UniPrintArgs(wchar_t *fmt, va_list args)
2614 {
2615 	wchar_t *str;
2616 	// Validate arguments
2617 	if (fmt == NULL)
2618 	{
2619 		return;
2620 	}
2621 
2622 	str = InternalFormatArgs(fmt, args, false);
2623 
2624 	UniPrintStr(str);
2625 
2626 	Free(str);
2627 }
2628 
2629 // Display the string
UniPrint(wchar_t * fmt,...)2630 void UniPrint(wchar_t *fmt, ...)
2631 {
2632 	va_list args;
2633 	// Validate arguments
2634 	if (fmt == NULL)
2635 	{
2636 		return;
2637 	}
2638 
2639 	va_start(args, fmt);
2640 	UniPrintArgs(fmt, args);
2641 	va_end(args);
2642 }
2643 
2644 // Display debug string with arguments
UniDebugArgs(wchar_t * fmt,va_list args)2645 void UniDebugArgs(wchar_t *fmt, va_list args)
2646 {
2647 	if (g_debug == false)
2648 	{
2649 		return;
2650 	}
2651 
2652 	UniPrintArgs(fmt, args);
2653 }
2654 
2655 // Display a debug string
UniDebug(wchar_t * fmt,...)2656 void UniDebug(wchar_t *fmt, ...)
2657 {
2658 	va_list args;
2659 	// Validate arguments
2660 	if (fmt == NULL)
2661 	{
2662 		return;
2663 	}
2664 
2665 	va_start(args, fmt);
2666 	UniDebugArgs(fmt, args);
2667 	va_end(args);
2668 }
2669 
2670 // Format a string (argument list)
UniFormatArgs(wchar_t * buf,UINT size,wchar_t * fmt,va_list args)2671 void UniFormatArgs(wchar_t *buf, UINT size, wchar_t *fmt, va_list args)
2672 {
2673 	wchar_t *ret;
2674 	// Validate arguments
2675 	if (buf == NULL || fmt == NULL)
2676 	{
2677 		return;
2678 	}
2679 	if (size == 1)
2680 	{
2681 		return;
2682 	}
2683 
2684 	// KS
2685 	KS_INC(KS_FORMAT_COUNT);
2686 
2687 	ret = InternalFormatArgs(fmt, args, false);
2688 
2689 	UniStrCpy(buf, size, ret);
2690 
2691 	Free(ret);
2692 }
2693 
2694 // Format the string, and copy it
CopyUniFormat(wchar_t * fmt,...)2695 wchar_t *CopyUniFormat(wchar_t *fmt, ...)
2696 {
2697 	wchar_t *ret, *str;
2698 	UINT size;
2699 	va_list args;
2700 	// Validate arguments
2701 	if (fmt == NULL)
2702 	{
2703 		return NULL;
2704 	}
2705 
2706 	size = MAX(UniStrSize(fmt) * 10, MAX_SIZE * 10);
2707 	str = Malloc(size);
2708 
2709 	va_start(args, fmt);
2710 	UniFormatArgs(str, size, fmt, args);
2711 
2712 	ret = UniCopyStr(str);
2713 	Free(str);
2714 	va_end(args);
2715 
2716 	return ret;
2717 }
2718 
2719 // Format the string
UniFormat(wchar_t * buf,UINT size,wchar_t * fmt,...)2720 void UniFormat(wchar_t *buf, UINT size, wchar_t *fmt, ...)
2721 {
2722 	va_list args;
2723 	// Validate arguments
2724 	if (buf == NULL || fmt == NULL)
2725 	{
2726 		return;
2727 	}
2728 
2729 	va_start(args, fmt);
2730 	UniFormatArgs(buf, size, fmt, args);
2731 	va_end(args);
2732 }
2733 
2734 // Flexible string comparison
UniSoftStrCmp(wchar_t * str1,wchar_t * str2)2735 int UniSoftStrCmp(wchar_t *str1, wchar_t *str2)
2736 {
2737 	UINT ret;
2738 	wchar_t *tmp1, *tmp2;
2739 	// Validate arguments
2740 	if (str1 == NULL && str2 == NULL)
2741 	{
2742 		return 0;
2743 	}
2744 	if (str1 == NULL)
2745 	{
2746 		return 1;
2747 	}
2748 	if (str2 == NULL)
2749 	{
2750 		return -1;
2751 	}
2752 
2753 	tmp1 = CopyUniStr(str1);
2754 	tmp2 = CopyUniStr(str2);
2755 
2756 	UniTrim(tmp1);
2757 	UniTrim(tmp2);
2758 
2759 	ret = UniStrCmpi(tmp1, tmp2);
2760 
2761 	Free(tmp1);
2762 	Free(tmp2);
2763 
2764 	return ret;
2765 }
2766 
2767 // Compare the strings in case-insensitive mode
UniStrCmpi(wchar_t * str1,wchar_t * str2)2768 int UniStrCmpi(wchar_t *str1, wchar_t *str2)
2769 {
2770 	UINT i;
2771 	// Validate arguments
2772 	if (str1 == NULL && str2 == NULL)
2773 	{
2774 		return 0;
2775 	}
2776 	if (str1 == NULL)
2777 	{
2778 		return 1;
2779 	}
2780 	if (str2 == NULL)
2781 	{
2782 		return -1;
2783 	}
2784 
2785 	// String comparison
2786 	i = 0;
2787 	while (true)
2788 	{
2789 		wchar_t c1, c2;
2790 		c1 = UniToUpper(str1[i]);
2791 		c2 = UniToUpper(str2[i]);
2792 		if (c1 > c2)
2793 		{
2794 			return 1;
2795 		}
2796 		else if (c1 < c2)
2797 		{
2798 			return -1;
2799 		}
2800 		if (str1[i] == 0 || str2[i] == 0)
2801 		{
2802 			return 0;
2803 		}
2804 		i++;
2805 	}
2806 }
2807 
2808 // Compare the string
UniStrCmp(wchar_t * str1,wchar_t * str2)2809 int UniStrCmp(wchar_t *str1, wchar_t *str2)
2810 {
2811 	// Validate arguments
2812 	if (str1 == NULL && str2 == NULL)
2813 	{
2814 		return 0;
2815 	}
2816 	if (str1 == NULL)
2817 	{
2818 		return 1;
2819 	}
2820 	if (str2 == NULL)
2821 	{
2822 		return -1;
2823 	}
2824 
2825 	return wcscmp(str1, str2);
2826 }
2827 
2828 // Uncapitalize the string
UniStrLower(wchar_t * str)2829 void UniStrLower(wchar_t *str)
2830 {
2831 	UINT i, len;
2832 	// Validate arguments
2833 	if (str == NULL)
2834 	{
2835 		return;
2836 	}
2837 
2838 	len = UniStrLen(str);
2839 	for (i = 0;i < len;i++)
2840 	{
2841 		str[i] = UniToLower(str[i]);
2842 	}
2843 }
2844 
2845 // Capitalize the string
UniStrUpper(wchar_t * str)2846 void UniStrUpper(wchar_t *str)
2847 {
2848 	UINT i, len;
2849 	// Validate arguments
2850 	if (str == NULL)
2851 	{
2852 		return;
2853 	}
2854 
2855 	len = UniStrLen(str);
2856 	for (i = 0;i < len;i++)
2857 	{
2858 		str[i] = UniToUpper(str[i]);
2859 	}
2860 }
2861 
2862 // Uncapitalize a character
UniToLower(wchar_t c)2863 wchar_t UniToLower(wchar_t c)
2864 {
2865 	if (c >= L'A' && c <= L'Z')
2866 	{
2867 		c += L'a' - L'A';
2868 	}
2869 
2870 	return c;
2871 }
2872 
2873 // Capitalize a character
UniToUpper(wchar_t c)2874 wchar_t UniToUpper(wchar_t c)
2875 {
2876 	if (c >= L'a' && c <= L'z')
2877 	{
2878 		c -= L'a' - L'A';
2879 	}
2880 
2881 	return c;
2882 }
2883 
2884 // String concatenation
UniStrCat(wchar_t * dst,UINT size,wchar_t * src)2885 UINT UniStrCat(wchar_t *dst, UINT size, wchar_t *src)
2886 {
2887 	UINT len1, len2, len_test;
2888 	// Validate arguments
2889 	if (dst == NULL || src == NULL)
2890 	{
2891 		return 0;
2892 	}
2893 	if (size != 0 && size < sizeof(wchar_t))
2894 	{
2895 		return 0;
2896 	}
2897 	if (size == sizeof(wchar_t))
2898 	{
2899 		wcscpy(dst, L"");
2900 		return 0;
2901 	}
2902 	if (size == 0)
2903 	{
2904 		// Ignore the length
2905 		size = 0x3fffffff;
2906 	}
2907 
2908 	len1 = UniStrLen(dst);
2909 	len2 = UniStrLen(src);
2910 	len_test = len1 + len2 + 1;
2911 	if (len_test > (size / sizeof(wchar_t)))
2912 	{
2913 		if (len2 <= (len_test - (size / sizeof(wchar_t))))
2914 		{
2915 			return 0;
2916 		}
2917 		len2 -= len_test - (size / sizeof(wchar_t));
2918 	}
2919 	Copy(&dst[len1], src, len2 * sizeof(wchar_t));
2920 	dst[len1 + len2] = 0;
2921 
2922 	return len1 + len2;
2923 }
2924 
2925 // String copy
UniStrCpy(wchar_t * dst,UINT size,wchar_t * src)2926 UINT UniStrCpy(wchar_t *dst, UINT size, wchar_t *src)
2927 {
2928 	UINT len;
2929 	// Validate arguments
2930 	if (dst == NULL || src == NULL)
2931 	{
2932 		if (src == NULL && dst != NULL)
2933 		{
2934 			if (size >= sizeof(wchar_t))
2935 			{
2936 				dst[0] = L'\0';
2937 			}
2938 		}
2939 		return 0;
2940 	}
2941 	if (dst == src)
2942 	{
2943 		return UniStrLen(src);
2944 	}
2945 	if (size != 0 && size < sizeof(wchar_t))
2946 	{
2947 		return 0;
2948 	}
2949 	if (size == sizeof(wchar_t))
2950 	{
2951 		wcscpy(dst, L"");
2952 		return 0;
2953 	}
2954 	if (size == 0)
2955 	{
2956 		// Ignore the length
2957 		size = 0x3fffffff;
2958 	}
2959 
2960 	// Check the length
2961 	len = UniStrLen(src);
2962 	if (len <= (size / sizeof(wchar_t) - 1))
2963 	{
2964 		Copy(dst, src, (len + 1) * sizeof(wchar_t));
2965 	}
2966 	else
2967 	{
2968 		len = size / sizeof(wchar_t) - 1;
2969 		Copy(dst, src, len * sizeof(wchar_t));
2970 		dst[len] = 0;
2971 	}
2972 
2973 	return len;
2974 }
2975 
2976 // Get the buffer size needed to store the string
UniStrSize(wchar_t * str)2977 UINT UniStrSize(wchar_t *str)
2978 {
2979 	// Validate arguments
2980 	if (str == NULL)
2981 	{
2982 		return 0;
2983 	}
2984 
2985 	return (UniStrLen(str) + 1) * sizeof(wchar_t);
2986 }
2987 
2988 // Get the length of the string
UniStrLen(wchar_t * str)2989 UINT UniStrLen(wchar_t *str)
2990 {
2991 	UINT i;
2992 	// Validate arguments
2993 	if (str == NULL)
2994 	{
2995 		return 0;
2996 	}
2997 
2998 	i = 0;
2999 	while (true)
3000 	{
3001 		if (str[i] == 0)
3002 		{
3003 			break;
3004 		}
3005 		i++;
3006 	}
3007 
3008 	return i;
3009 }
3010 
3011