1 /*
2  *  unicode.c
3  *
4  *  $Id$
5  *
6  *  ODBC unicode functions
7  *
8  *  The iODBC driver manager.
9  *
10  *  Copyright (C) 1996-2021 OpenLink Software <iodbc@openlinksw.com>
11  *  All Rights Reserved.
12  *
13  *  This software is released under the terms of either of the following
14  *  licenses:
15  *
16  *      - GNU Library General Public License (see LICENSE.LGPL)
17  *      - The BSD License (see LICENSE.BSD).
18  *
19  *  Note that the only valid version of the LGPL license as far as this
20  *  project is concerned is the original GNU Library General Public License
21  *  Version 2, dated June 1991.
22  *
23  *  While not mandated by the BSD license, any patches you make to the
24  *  iODBC source code may be contributed back into the iODBC project
25  *  at your discretion. Contributions will benefit the Open Source and
26  *  Data Access community as a whole. Submissions may be made at:
27  *
28  *      http://www.iodbc.org
29  *
30  *
31  *  GNU Library Generic Public License Version 2
32  *  ============================================
33  *  This library is free software; you can redistribute it and/or
34  *  modify it under the terms of the GNU Library General Public
35  *  License as published by the Free Software Foundation; only
36  *  Version 2 of the License dated June 1991.
37  *
38  *  This library is distributed in the hope that it will be useful,
39  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
40  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41  *  Library General Public License for more details.
42  *
43  *  You should have received a copy of the GNU Library General Public
44  *  License along with this library; if not, write to the Free
45  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
46  *
47  *
48  *  The BSD License
49  *  ===============
50  *  Redistribution and use in source and binary forms, with or without
51  *  modification, are permitted provided that the following conditions
52  *  are met:
53  *
54  *  1. Redistributions of source code must retain the above copyright
55  *     notice, this list of conditions and the following disclaimer.
56  *  2. Redistributions in binary form must reproduce the above copyright
57  *     notice, this list of conditions and the following disclaimer in
58  *     the documentation and/or other materials provided with the
59  *     distribution.
60  *  3. Neither the name of OpenLink Software Inc. nor the names of its
61  *     contributors may be used to endorse or promote products derived
62  *     from this software without specific prior written permission.
63  *
64  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
68  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71  *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75  */
76 
77 #define UNICODE
78 
79 #include <iodbc.h>
80 
81 #include <sql.h>
82 #include <sqlext.h>
83 #include <sqltypes.h>
84 
85 #include <stdlib.h>
86 #include <string.h>
87 
88 #ifdef WIN32
89 #if _MSC_VER < 1300
90 #include <ansiapi.h>
91 #endif
92 #include <stringapiset.h>
93 #endif
94 
95 #include "unicode.h"
96 
97 
98 #ifndef UNICHAR_DEFINED
99 #define UNICHAR_DEFINED
100 typedef int unichar;				/*!< 31-bit unicode values, negative ones are invalid */
101 #endif
102 
103 #define UNICHAR_EOD		((unichar)(-2))	/*!< End of source buffer reached, no data to convert */
104 #define UNICHAR_NO_DATA		((unichar)(-3))	/*!< Source buffer is too short, but nonempty (contains part of a char) */
105 #define UNICHAR_NO_ROOM		((unichar)(-4))	/*!< Target buffer is too short */
106 #define UNICHAR_BAD_ENCODING	((unichar)(-5))	/*!< Invalid character decoded from invalid string */
107 #define UNICHAR_OUT_OF_WCHAR	((unichar)(-6))	/*!< The encoded data are valid but the encoded character is out of 16-bit range and will not fit 2-byte wchar_t. */
108 
109 typedef const char *__constcharptr;
110 
111 static unichar eh_decode_char__UTF16BE (__constcharptr *src_begin_ptr,
112 	const char *src_buf_end, ...);
113 static char *eh_encode_char__UTF16BE (unichar char_to_put, char *tgt_buf,
114 	char *tgt_buf_end, ...);
115 static unichar eh_decode_char__UTF16LE (__constcharptr *src_begin_ptr,
116 	const char *src_buf_end, ...);
117 static char *eh_encode_char__UTF16LE (unichar char_to_put, char *tgt_buf,
118 	char *tgt_buf_end, ...);
119 
120 static size_t _calc_len_for_utf8 (IODBC_CHARSET charset, void * str,
121 	int size);
122 static size_t _wcxtoutf8 (IODBC_CHARSET charset, void * wstr, char * ustr,
123 	int size);
124 static size_t _wcxntoutf8 (IODBC_CHARSET charset, void * wstr, char *ustr,
125 	int wlen, int size, int * converted);
126 static size_t _utf8towcx (IODBC_CHARSET charset, char * ustr, void * wstr,
127 	int size);
128 
129 static size_t _WCSLEN(IODBC_CHARSET charset, void *str);
130 
131 static size_t dm_UWtoA(wchar_t *src, int ilen, char *dest, int olen);
132 static size_t dm_AtoUW(char *src, int ilen, wchar_t *dest, size_t olen);
133 
134 #ifndef MAX
135 # define MAX(X,Y)	(X > Y ? X : Y)
136 # define MIN(X,Y)	(X < Y ? X : Y)
137 #endif
138 
139 
140 #if !defined(HAVE_WCSLEN)
141 size_t
wcslen(const wchar_t * wcs)142 wcslen (const wchar_t * wcs)
143 {
144   size_t len = 0;
145 
146   while (*wcs++ != L'\0')
147     len++;
148 
149   return len;
150 }
151 #endif
152 
153 
154 #if !defined(HAVE_WCSCPY)
155 wchar_t *
wcscpy(wchar_t * wcd,const wchar_t * wcs)156 wcscpy (wchar_t * wcd, const wchar_t * wcs)
157 {
158   wchar_t *dst = wcd;
159 
160   while ((*dst++ = *wcs++) != L'\0')
161     ;
162 
163   return wcd;
164 }
165 #endif
166 
167 
168 #if !defined (HAVE_WCSNCPY)
169 wchar_t *
wcsncpy(wchar_t * wcd,const wchar_t * wcs,size_t n)170 wcsncpy (wchar_t * wcd, const wchar_t * wcs, size_t n)
171 {
172   wchar_t *dst = wcd;
173   size_t len = 0;
174 
175   while ( len < n && (*dst++ = *wcs++) != L'\0')
176     len++;
177 
178   for (; len < n; len++)
179     *dst++ = L'\0';
180 
181   return wcd;
182 }
183 #endif
184 
185 #if !defined(HAVE_WCSCHR)
wcschr(const wchar_t * wcs,const wchar_t wc)186 wchar_t* wcschr(const wchar_t *wcs, const wchar_t wc)
187 {
188   do
189     if(*wcs == wc)
190       return (wchar_t*) wcs;
191   while(*wcs++ != L'\0');
192 
193   return NULL;
194 }
195 #endif
196 
197 #if !defined(HAVE_WCSCAT)
wcscat(wchar_t * dest,const wchar_t * src)198 wchar_t* wcscat(wchar_t *dest, const wchar_t *src)
199 {
200   wchar_t *s1 = dest;
201   const wchar_t *s2 = src;
202   wchar_t c;
203 
204   do
205     c = *s1 ++;
206   while(c != L'\0');
207 
208   s1 -= 2;
209 
210   do
211     {
212       c = *s2 ++;
213       *++s1 = c;
214     }
215   while(c != L'\0');
216 
217   return dest;
218 }
219 #endif
220 
221 #if !defined(HAVE_WCSCMP)
wcscmp(const wchar_t * s1,const wchar_t * s2)222 int wcscmp (const wchar_t* s1, const wchar_t* s2)
223 {
224   wchar_t c1, c2;
225 
226   if (s1 == s2)
227     return 0;
228 
229   do
230     {
231       c1 = *s1++;
232       c2 = *s2++;
233       if(c1 == L'\0')
234         break;
235     }
236   while (c1 == c2);
237 
238   return c1 - c2;
239 }
240 #endif
241 
242 
243 #if !defined(HAVE_TOWLOWER)
244 
245 #if (defined (__APPLE__) && !(defined (NO_FRAMEWORKS) || defined (_LP64)))
246 
247 #include <Carbon/Carbon.h>
248 
249 wchar_t
towlower(wchar_t wc)250 towlower (wchar_t wc)
251 {
252   CFMutableStringRef strRef = CFStringCreateMutable (NULL, 0);
253   UniChar c = (UniChar) wc;
254   wchar_t wcs;
255 
256   CFStringAppendCharacters (strRef, &c, 1);
257   CFStringLowercase (strRef, NULL);
258   wcs = CFStringGetCharacterAtIndex (strRef, 0);
259   CFRelease (strRef);
260 
261   return wcs;
262 }
263 
264 #else
265 
266 /* Use dummy function */
267 wchar_t
towlower(wchar_t wc)268 towlower (wchar_t wc)
269 {
270   return wc;
271 }
272 
273 #endif /* __APPLE__ */
274 #endif /* !HAVE_TOWLOWER */
275 
276 
277 #if !defined(HAVE_WCSNCASECMP)
wcsncasecmp(const wchar_t * s1,const wchar_t * s2,size_t n)278 int wcsncasecmp (const wchar_t* s1, const wchar_t* s2, size_t n)
279 {
280   wchar_t c1, c2;
281 
282   if (s1 == s2 || n ==0)
283     return 0;
284 
285   do
286     {
287       c1 = towlower(*s1++);
288       c2 = towlower(*s2++);
289       if(c1 == L'\0' || c1 != c2)
290         return c1 - c2;
291     } while (--n > 0);
292 
293   return c1 - c2;
294 }
295 #endif
296 
297 
298 /* UTF-16BE */
299 
300 static unichar
eh_decode_char__UTF16BE(__constcharptr * src_begin_ptr,const char * src_buf_end,...)301 eh_decode_char__UTF16BE (__constcharptr *src_begin_ptr, const char *src_buf_end, ...)
302 {
303 /* As is in RFC 2781...
304    U' = yyyyyyyyyyxxxxxxxxxx
305    W1 = 110110yyyyyyyyyy
306    W2 = 110111xxxxxxxxxx
307 */
308   unsigned char *src_begin = (unsigned char *)(src_begin_ptr[0]);
309   unsigned char hi, lo, hiaddon, loaddon;
310   unichar acc /* W1 */, accaddon /* W2 */;
311   if (src_begin >= (unsigned char *)src_buf_end)
312     return UNICHAR_EOD;
313   if (src_begin+1 >= (unsigned char *)src_buf_end)
314     return UNICHAR_NO_DATA;
315   hi = src_begin[0];
316   lo = src_begin[1];
317   acc = (hi << 8) | lo;
318   if (0xFFFE == acc)
319     return UNICHAR_BAD_ENCODING; /* Maybe UTF16LE ? */
320   switch (acc & 0xFC00)
321     {
322       case 0xD800:
323 	if (src_begin+3 >= (unsigned char *)src_buf_end)
324 	  return UNICHAR_NO_DATA;
325 	hiaddon = src_begin[2];
326 	loaddon = src_begin[3];
327 	accaddon = (hiaddon << 8) | loaddon;
328 	if (0xDC00 != (accaddon & 0xFC00))
329 	  return UNICHAR_BAD_ENCODING; /* No low-half after hi-half ? */
330 	src_begin_ptr[0] += 4;
331 	return 0x10000 + (((acc & 0x3FF) << 10) | (accaddon & 0x3FF));
332       case 0xDC00:
333 	return UNICHAR_BAD_ENCODING; /* Low-half first ? */
334       default:
335 	src_begin_ptr[0] += 2;
336 	return acc;
337     }
338 }
339 
340 
341 static char *
eh_encode_char__UTF16BE(unichar char_to_put,char * tgt_buf,char * tgt_buf_end,...)342 eh_encode_char__UTF16BE (unichar char_to_put, char *tgt_buf, char *tgt_buf_end, ...)
343 {
344   if (char_to_put < 0)
345     return tgt_buf;
346   if (char_to_put & ~0xFFFF)
347     {
348       if (tgt_buf+4 > tgt_buf_end)
349 	return (char *)UNICHAR_NO_ROOM;
350       char_to_put -= 0x10000;
351       tgt_buf[0] = (unsigned char)(0xD8 | ((char_to_put >> 18) & 0x03));
352       tgt_buf[1] = (unsigned char)((char_to_put >> 10) & 0xFF);
353       tgt_buf[2] = (unsigned char)(0xDC | ((char_to_put >> 8) & 0x03));
354       tgt_buf[3] = (unsigned char)(char_to_put & 0xFF);
355       return tgt_buf+4;
356     }
357   if (0xD800 == (char_to_put & 0xF800))
358     return tgt_buf;
359   if (tgt_buf+2 > tgt_buf_end)
360     return (char *)UNICHAR_NO_ROOM;
361   tgt_buf[0] = (unsigned char)(char_to_put >> 8);
362   tgt_buf[1] = (unsigned char)(char_to_put & 0xFF);
363   return tgt_buf+2;
364 }
365 
366 
367 /* UTF-16LE */
368 
369 static unichar
eh_decode_char__UTF16LE(__constcharptr * src_begin_ptr,const char * src_buf_end,...)370 eh_decode_char__UTF16LE (__constcharptr *src_begin_ptr, const char *src_buf_end, ...)
371 {
372 /* As is in RFC 2781...
373    U' = yyyyyyyyyyxxxxxxxxxx
374    W1 = 110110yyyyyyyyyy
375    W2 = 110111xxxxxxxxxx
376 */
377   unsigned char *src_begin = (unsigned char *)(src_begin_ptr[0]);
378   unsigned char hi, lo, hiaddon, loaddon;
379   unichar acc /* W1 */, accaddon /* W2 */;
380   if (src_begin >= (unsigned char *)src_buf_end)
381     return UNICHAR_EOD;
382   if (src_begin+1 >= (unsigned char *)src_buf_end)
383     return UNICHAR_NO_DATA;
384   hi = src_begin[1];
385   lo = src_begin[0];
386   acc = (hi << 8) | lo;
387   if (0xFFFE == acc)
388     return UNICHAR_BAD_ENCODING; /* Maybe UTF16BE ? */
389   switch (acc & 0xFC00)
390     {
391       case 0xD800:
392 	if (src_begin+3 >= (unsigned char *)src_buf_end)
393 	  return UNICHAR_NO_DATA;
394 	hiaddon = src_begin[3];
395 	loaddon = src_begin[2];
396 	accaddon = (hiaddon << 8) | loaddon;
397 	if (0xDC00 != (accaddon & 0xFC00))
398 	  return UNICHAR_BAD_ENCODING; /* No low-half after hi-half ? */
399 	src_begin_ptr[0] += 4;
400 	return 0x10000 + (((acc & 0x3FF) << 10) | (accaddon & 0x3FF));
401       case 0xDC00:
402 	return UNICHAR_BAD_ENCODING; /* Low-half first ? */
403       default:
404 	src_begin_ptr[0] += 2;
405 	return acc;
406     }
407 }
408 
409 
410 static char *
eh_encode_char__UTF16LE(unichar char_to_put,char * tgt_buf,char * tgt_buf_end,...)411 eh_encode_char__UTF16LE (unichar char_to_put, char *tgt_buf, char *tgt_buf_end, ...)
412 {
413   if (char_to_put < 0)
414     return tgt_buf;
415   if (char_to_put & ~0xFFFF)
416     {
417       if (tgt_buf+4 > tgt_buf_end)
418 	return (char *)UNICHAR_NO_ROOM;
419       char_to_put -= 0x10000;
420       tgt_buf[1] = (unsigned char)(0xD8 | ((char_to_put >> 18) & 0x03));
421       tgt_buf[0] = (unsigned char)((char_to_put >> 10) & 0xFF);
422       tgt_buf[3] = (unsigned char)(0xDC | ((char_to_put >> 8) & 0x03));
423       tgt_buf[2] = (unsigned char)(char_to_put & 0xFF);
424       return tgt_buf+4;
425     }
426   if (0xD800 == (char_to_put & 0xF800))
427     return tgt_buf;
428   if (tgt_buf+2 > tgt_buf_end)
429     return (char *)UNICHAR_NO_ROOM;
430   tgt_buf[1] = (unsigned char)(char_to_put >> 8);
431   tgt_buf[0] = (unsigned char)(char_to_put & 0xFF);
432   return tgt_buf+2;
433 }
434 
435 
436 
437 SQLCHAR *
dm_SQL_W2A(SQLWCHAR * inStr,int size)438 dm_SQL_W2A (SQLWCHAR * inStr, int size)
439 {
440   SQLCHAR *outStr = NULL;
441   size_t len;
442 
443   if (inStr == NULL)
444     return NULL;
445 
446   if (size == SQL_NTS)
447    len = wcslen (inStr);
448   else if (size < 0)
449    return NULL;
450   else
451     len = (size_t)size;
452 
453 # ifdef WIN32
454   if ((outStr = (SQLCHAR *) calloc (len * UTF8_MAX_CHAR_LEN + 1, 1)) != NULL)
455     {
456       if (len > 0)
457 	OPL_W2A (inStr, outStr, len);
458       outStr[len] = '\0';
459     }
460 #else
461   if ((outStr = (SQLCHAR *) calloc (len * MB_CUR_MAX + 1, 1)) != NULL)
462     {
463       if (len > 0)
464         dm_UWtoA(inStr, len, outStr, len * MB_CUR_MAX);
465     }
466 #endif
467 
468   return outStr;
469 }
470 
471 
472 SQLWCHAR *
dm_SQL_A2W(SQLCHAR * inStr,int size)473 dm_SQL_A2W (SQLCHAR * inStr, int size)
474 {
475   SQLWCHAR *outStr = NULL;
476   size_t len;
477 
478   if (inStr == NULL)
479     return NULL;
480 
481   if (size == SQL_NTS)
482     len = strlen ((char *) inStr);
483   else if (size < 0)
484     return NULL;
485   else
486     len = (size_t)size;
487 
488   if ((outStr = (SQLWCHAR *) calloc (len + 1, sizeof (SQLWCHAR))) != NULL)
489     {
490       if (len > 0)
491         dm_AtoUW(inStr, len, outStr, len);
492     }
493 
494   return outStr;
495 }
496 
497 
498 int
dm_StrCopyOut2_A2W(SQLCHAR * inStr,SQLWCHAR * outStr,SQLSMALLINT size,WORD * result)499 dm_StrCopyOut2_A2W (
500   SQLCHAR	* inStr,
501   SQLWCHAR	* outStr,
502   SQLSMALLINT	  size,
503   WORD		* result)
504 {
505   size_t length;
506 
507   if (!inStr)
508     return -1;
509 
510   length = strlen ((char *) inStr);
511 
512   if (result)
513     *result = (SQLSMALLINT) length;
514 
515   if (!outStr)
516     return 0;
517 
518   if (size >= length + 1)
519     {
520       if (length > 0)
521         length = dm_AtoUW(inStr, length, outStr, length);
522 
523       outStr[length] = L'\0';
524       return 0;
525     }
526   if (size > 0)
527     {
528       length = dm_AtoUW(inStr, length, outStr, size);
529       outStr[length] = L'\0';
530     }
531   return -1;
532 }
533 
534 int
dm_StrCopyOut2_W2A(SQLWCHAR * inStr,SQLCHAR * outStr,SQLSMALLINT size,WORD * result)535 dm_StrCopyOut2_W2A (
536   SQLWCHAR	* inStr,
537   SQLCHAR	* outStr,
538   SQLSMALLINT	  size,
539   WORD		* result)
540 {
541   size_t length;
542 
543   if (!inStr)
544     return -1;
545 
546   length = wcslen (inStr);
547 
548   if (result)
549     *result = (SQLSMALLINT) length;
550 
551   if (!outStr)
552     return 0;
553 
554   if (size >= length + 1)
555     {
556       if (length > 0)
557         length = dm_UWtoA(inStr, length, outStr, length);
558 
559       outStr[length] = '\0';
560       return 0;
561     }
562   if (size > 0)
563     {
564       length = dm_UWtoA(inStr, length, outStr, size);
565       outStr[length] = '\0';
566     }
567   return -1;
568 }
569 
570 
571 SQLWCHAR *
dm_strcpy_A2W(SQLWCHAR * destStr,SQLCHAR * sourStr)572 dm_strcpy_A2W (SQLWCHAR * destStr, SQLCHAR * sourStr)
573 {
574   size_t length;
575 
576   if (!sourStr || !destStr)
577     return destStr;
578 
579   length = strlen ((char *) sourStr);
580 
581   if (length > 0)
582     length = dm_AtoUW(sourStr, length, destStr, length);
583 
584   destStr[length] = L'\0';
585   return destStr;
586 }
587 
588 
589 SQLCHAR *
dm_strcpy_W2A(SQLCHAR * destStr,SQLWCHAR * sourStr)590 dm_strcpy_W2A (SQLCHAR * destStr, SQLWCHAR * sourStr)
591 {
592   size_t length;
593 
594   if (!sourStr || !destStr)
595     return destStr;
596 
597   length = wcslen (sourStr);
598 
599   if (length > 0)
600     length = dm_UWtoA(sourStr, length, destStr, length);
601 
602   destStr[length] = '\0';
603   return destStr;
604 }
605 
606 
607 /* encode */
608 #define LEN_FOR_UTF8(Char, Len)		        \
609   if (Char < 0x80)                              \
610     {                                           \
611       Len = 1;                                  \
612     }                                           \
613   else if (Char < 0x800)                        \
614     {                                           \
615       Len = 2;                                  \
616     }                                           \
617   else if (Char < 0x10000)                      \
618     {                                           \
619       Len = 3;                                  \
620     }                                           \
621   else if (Char < 0x110000)                     \
622     {                                           \
623       Len = 4;                                  \
624     }                                           \
625   else                                          \
626     {                                           \
627       Len = 1;                                  \
628     }
629 
630 #define CONV_TO_UTF8(Char, Len, First)		\
631   if (Char < 0x80)                              \
632     {                                           \
633       Len = 1;                                  \
634       First = 0;                                \
635     }                                           \
636   else if (Char < 0x800)                        \
637     {                                           \
638       Len = 2;                                  \
639       First = 0xC0;                             \
640     }                                           \
641   else if (Char < 0x10000)                      \
642     {                                           \
643       Len = 3;                                  \
644       First = 0xE0;                             \
645     }                                           \
646   else if (Char < 0x110000)                     \
647     {                                           \
648       Len = 4;                                  \
649       First = 0xf0;                             \
650     }                                           \
651   else                                          \
652     {                                           \
653       Len = 1;                                  \
654       First = 0;                                \
655       Char = '?';                               \
656     }
657 
658 
659 /* decode */
660 #define UTF8_COMPUTE(Char, Mask, Len)					      \
661   if (Char < 128)							      \
662     {									      \
663       Len = 1;								      \
664       Mask = 0x7f;							      \
665     }									      \
666   else if ((Char & 0xe0) == 0xc0)					      \
667     {									      \
668       Len = 2;								      \
669       Mask = 0x1f;							      \
670     }									      \
671   else if ((Char & 0xf0) == 0xe0)					      \
672     {									      \
673       Len = 3;								      \
674       Mask = 0x0f;							      \
675     }									      \
676   else if ((Char & 0xf8) == 0xf0)					      \
677     {									      \
678       Len = 4;								      \
679       Mask = 0x07;							      \
680     }									      \
681   else									      \
682     Len = -1;
683 
684 
685 
686 static size_t
_WCHARSIZE(IODBC_CHARSET charset)687 _WCHARSIZE(IODBC_CHARSET charset)
688 {
689   switch(charset)
690     {
691     case CP_UTF8: return 1;
692     case CP_UTF16: return sizeof(ucs2_t);
693     case CP_UCS4: return sizeof(ucs4_t);
694     }
695 }
696 
697 
698 static size_t
_WCHARSIZE_ALLOC(IODBC_CHARSET charset)699 _WCHARSIZE_ALLOC(IODBC_CHARSET charset)
700 {
701   switch(charset)
702     {
703     case CP_UTF8: return UTF8_MAX_CHAR_LEN;
704     case CP_UTF16: return sizeof(ucs2_t) * 2;
705     case CP_UCS4: return sizeof(ucs4_t);
706     }
707 }
708 
709 
710 static size_t
_utf16_calc_len_for_utf8(ucs2_t * str,int size)711 _utf16_calc_len_for_utf8 (ucs2_t *str, int size)
712 {
713   size_t len = 0;
714   ucs4_t wc;
715   char *us = (char *) str;
716   char *us_end;
717   size_t utf8_len = 0;
718 
719   if (!str)
720     return len;
721 
722   us_end = (char *)(str + size);
723 
724   while (size > 0)
725     {
726 #ifdef WORDS_BIGENDIAN
727       wc = (ucs4_t) eh_decode_char__UTF16BE((__constcharptr *) &us, us_end);
728 #else
729       wc = (ucs4_t) eh_decode_char__UTF16LE((__constcharptr *) &us, us_end);
730 #endif
731       if (wc == UNICHAR_EOD || wc == UNICHAR_NO_DATA || wc == UNICHAR_BAD_ENCODING)
732         break;
733 
734       LEN_FOR_UTF8(wc, utf8_len);
735       len += utf8_len;
736 
737       size--;
738     }
739 
740   return len;
741 }
742 
743 static size_t
_ucs4_calc_len_for_utf8(ucs4_t * str,int size)744 _ucs4_calc_len_for_utf8 (ucs4_t *str, int size)
745 {
746   size_t len = 0;
747   ucs4_t wc;
748   size_t utf8_len = 0;
749 
750   if (!str)
751     return len;
752 
753   while (size > 0)
754     {
755       wc = *str;
756 
757       LEN_FOR_UTF8(wc, utf8_len);
758       len += utf8_len;
759 
760       str++;
761       size--;
762     }
763 
764   return len;
765 }
766 
767 
768 static size_t
_calc_len_for_utf8(IODBC_CHARSET charset,void * str,int size)769 _calc_len_for_utf8 (IODBC_CHARSET charset, void * str, int size)
770 {
771   if (!str)
772     return 0;
773 
774   if (size == SQL_NTS)
775     size = _WCSLEN (charset, str);
776 
777   if (charset == CP_UTF16)
778     return _utf16_calc_len_for_utf8 ((ucs2_t*)str, size);
779   else
780     return _ucs4_calc_len_for_utf8 ((ucs4_t*)str, size);
781 }
782 
783 
784 
785 static size_t
utf8_len(SQLCHAR * p,int size)786 utf8_len (SQLCHAR * p, int size)
787 {
788   size_t len = 0;
789 
790   if (!*p)
791     return 0;
792 
793   if (size == SQL_NTS)
794     while (*p)
795       {
796 	for (p++; (*p & 0xC0) == 0x80; p++)
797 	  ;
798 	len++;
799       }
800   else
801     while (size > 0)
802       {
803 	for (p++, size--; (size > 0) && ((*p & 0xC0) == 0x80); p++, size--)
804 	  ;
805 	len++;
806       }
807   return len;
808 }
809 
810 
811 /*
812  *  size      - size of buffer for output utf8 string in bytes
813  *  return    - length of output utf8 string
814  */
815 static size_t
wcstoutf8(wchar_t * wstr,char * ustr,int size_bytes)816 wcstoutf8 (wchar_t *wstr, char *ustr, int size_bytes)
817 {
818   return _wcxtoutf8 (CP_DEF, (void *)wstr, ustr, size_bytes);
819 }
820 
821 static size_t
_utf16ntoutf8(ucs2_t * wstr,char * ustr,int wlen,int size_bytes,int * converted)822 _utf16ntoutf8 (ucs2_t *wstr, char *ustr, int wlen, int size_bytes, int *converted)
823 {
824   int len;
825   ucs4_t wc;
826   int first;
827   int i;
828   int count = 0;
829   char *us0 = (char *) wstr;
830   char *us = (char *) wstr;
831   char *us_end;
832   int _converted = 0;
833 
834   if (!wstr)
835     return 0;
836 
837   us_end = (char *)(wstr + wlen);
838 
839   while(_converted < wlen && count < size_bytes)
840     {
841 #ifdef WORDS_BIGENDIAN
842       wc = (ucs4_t) eh_decode_char__UTF16BE((__constcharptr *) &us, us_end);
843 #else
844       wc = (ucs4_t) eh_decode_char__UTF16LE((__constcharptr *) &us, us_end);
845 #endif
846       if (wc == UNICHAR_EOD || wc == UNICHAR_NO_DATA || wc == UNICHAR_BAD_ENCODING)
847         break;
848 
849       CONV_TO_UTF8(wc, len, first);
850 
851       if (size_bytes - count < len)
852 	{
853 	  if (converted)
854 	    *converted = _converted;
855 	  return count;
856 	}
857 
858       for (i = len - 1; i > 0; --i)
859 	{
860 	  ustr[i] = (wc & 0x3f) | 0x80;
861 	  wc >>= 6;
862 	}
863       ustr[0] = wc | first;
864 
865       ustr += len;
866       count += len;
867       _converted = (us - us0) / sizeof(ucs2_t);
868     }
869 
870   if (converted)
871     *converted = _converted;
872 
873   return count;
874 }
875 
876 
877 /*
878  *  wlen      - length of input *wstr string in symbols(for utf8 in bytes)
879  *  size     - size of buffer ( *ustr string) in bytes
880  *  converted - number of converted symbols from *wstr(for utf8 in bytes)
881  *
882  *  Return    - length of output utf8 string
883  */
884 static size_t
_wcxntoutf8(IODBC_CHARSET charset,void * wstr,char * ustr,int wlen,int size_bytes,int * converted)885 _wcxntoutf8 (
886   IODBC_CHARSET   charset,
887   void		* wstr,
888   char		* ustr,
889   int		  wlen,
890   int		  size_bytes,
891   int	 	* converted)
892 {
893   int len;
894   ucs4_t c;
895   int first;
896   int i;
897   int count = 0;
898   int _converted = 0;
899   ucs4_t *u4str = (ucs4_t *)wstr;
900   wchar_t *sstr = (wchar_t *)wstr;
901 
902   if (!wstr)
903     return 0;
904 
905   if (charset == CP_UTF8)
906     {
907       unsigned char *u8str = (unsigned char*)wstr;
908       int mask;
909 
910       while (_converted < wlen && count < size_bytes)
911         {
912           UTF8_COMPUTE(*u8str, mask, len);
913 
914           if (size_bytes - count < len)
915 	    {
916 	      if (converted)
917 	        *converted = _converted;
918 	      return count;
919 	    }
920 
921           for (i = 0; i < len; i++)
922 	    *ustr++ = *u8str++;
923 
924 	  count += len;
925           _converted+=len;
926         }
927 
928       if (converted)
929         *converted = _converted;
930 
931       return count;
932     }
933   else if (charset == CP_UTF16)
934     {
935       return _utf16ntoutf8 ((ucs2_t *) wstr, ustr, wlen, size_bytes, converted);
936     }
937   else
938     {
939       while (_converted < wlen && count < size_bytes)
940         {
941           switch(charset)
942             {
943             case CP_UCS4: c = (ucs4_t)*u4str; break;
944             default:      c = (ucs4_t)*sstr;  break;
945             }
946 
947           CONV_TO_UTF8(c, len, first);
948 
949           if (size_bytes - count < len)
950 	    {
951 	      if (converted)
952 	        *converted = _converted;
953 	      return count;
954 	    }
955 
956           for (i = len - 1; i > 0; --i)
957 	    {
958 	      ustr[i] = (c & 0x3f) | 0x80;
959 	      c >>= 6;
960 	    }
961           ustr[0] = c | first;
962 
963           ustr += len;
964           count += len;
965           _converted++;
966 
967           switch(charset)
968             {
969             case CP_UCS4: u4str++; break;
970             default:      sstr++;  break;
971             }
972         }
973 
974       if (converted)
975         *converted = _converted;
976 
977       return count;
978     }
979 }
980 
981 
982 /*
983  *  size      - size of buffer for output utf8 string in bytes
984  *  return    - length of output utf8 string in bytes
985  */
986 static size_t
_wcxtoutf8(IODBC_CHARSET charset,void * wstr,char * ustr,int size_bytes)987 _wcxtoutf8 (IODBC_CHARSET charset, void * wstr, char * ustr, int size_bytes)
988 {
989   if (!wstr)
990     return 0;
991 
992   return _wcxntoutf8 (charset, wstr, ustr, _WCSLEN(charset, wstr), size_bytes, NULL);
993 }
994 
995 
996 /*
997  *  wlen      - length of input *wstr string in symbols
998  *  size     - size of buffer ( *ustr string) in bytes
999  *  converted - number of converted symbols from *wstr
1000  *
1001  *  Return    - length of output utf8 string
1002  */
1003 static size_t
wcsntoutf8(wchar_t * wstr,char * ustr,int wlen,int size,int * converted)1004 wcsntoutf8 (wchar_t *wstr, char *ustr, int wlen, int size,
1005     int *converted)
1006 {
1007   if (!wstr)
1008     return 0;
1009 
1010   return _wcxntoutf8 (CP_DEF, (void*)wstr, ustr, wlen, size, converted);
1011 }
1012 
1013 
1014 
1015 static SQLCHAR *
strdup_WtoU8(SQLWCHAR * str)1016 strdup_WtoU8 (SQLWCHAR * str)
1017 {
1018   SQLCHAR *ret;
1019   int len;
1020 
1021   if (!str)
1022     return NULL;
1023 
1024   len = _calc_len_for_utf8 (CP_DEF, str, SQL_NTS);
1025   if ((ret = (SQLCHAR *) malloc (len + 1)) == NULL)
1026     return NULL;
1027 
1028   len = wcstoutf8 (str, (char *)ret, len);
1029   ret[len] = '\0';
1030 
1031   return ret;
1032 }
1033 
1034 
1035 /*
1036  *  size      - size of buffer for output string in symbols (SQLWCHAR)
1037  *  return    - length of output SQLWCHAR string
1038  */
1039 static size_t
utf8towcs(char * ustr,SQLWCHAR * wstr,int size)1040 utf8towcs (char *ustr, SQLWCHAR *wstr, int size)
1041 {
1042   return _utf8towcx (CP_DEF, ustr, (void *)wstr, size);
1043 }
1044 
1045 
1046 /*
1047  *  ulen      - length of input *ustr string in bytes
1048  *  size      - size of buffer ( *wstr string) in symbols
1049  *  converted - number of converted bytes from *ustr
1050  *
1051  *  Return    - length of output wcs string
1052  */
1053 static size_t
_utf8ntoutf16(char * ustr,ucs2_t * wstr,int ulen,int size,int * converted)1054 _utf8ntoutf16 (
1055   char		* ustr,
1056   ucs2_t	* wstr,
1057   int		  ulen,
1058   int		  size,
1059   int		* converted)
1060 {
1061   int i;
1062   int mask = 0;
1063   int len;
1064   SQLCHAR c;
1065   ucs4_t wc;
1066   int count = 0;
1067   int _converted = 0;
1068   char *rc;
1069   char *us = (char*) wstr;
1070   char *us_end = (char*) (wstr + size);
1071 
1072   if (!ustr)
1073     return 0;
1074 
1075   while ((_converted < ulen) && (count < size))
1076     {
1077       c = *ustr;
1078       UTF8_COMPUTE (c, mask, len);
1079       if ((len == -1) || (_converted + len > ulen))
1080 	{
1081 	  if (converted)
1082 	    *converted = _converted;
1083 	  return count;
1084 	}
1085 
1086       wc = c & mask;
1087       for (i = 1; i < len; i++)
1088 	{
1089 	  if ((ustr[i] & 0xC0) != 0x80)
1090 	    {
1091 	      if (converted)
1092 		*converted = _converted;
1093 	      return count;
1094 	    }
1095 	  wc <<= 6;
1096 	  wc |= (ustr[i] & 0x3F);
1097 	}
1098 
1099 #ifdef WORDS_BIGENDIAN
1100       rc = eh_encode_char__UTF16BE ((unichar)wc, us, us_end);
1101 #else
1102       rc = eh_encode_char__UTF16LE ((unichar)wc, us, us_end);
1103 #endif
1104       if ((char *)UNICHAR_NO_ROOM == rc)
1105         break;
1106 
1107       count += (rc - us) / sizeof(ucs2_t);
1108       us = rc;
1109       ustr += len;
1110       _converted += len;
1111     }
1112   if (converted)
1113     *converted = _converted;
1114   return count;
1115 }
1116 
1117 
1118 /*
1119  *  ulen      - length of input *ustr string in bytes
1120  *  size      - size of buffer ( *wstr string) in symbols
1121  *  converted - number of converted bytes from *ustr
1122  *
1123  *  Return    - length of output wcs string
1124  */
1125 static size_t
_utf8ntowcx(IODBC_CHARSET charset,char * ustr,void * wstr,int ulen,int size,int * converted)1126 _utf8ntowcx (
1127   IODBC_CHARSET   charset,
1128   char		* ustr,
1129   void		* wstr,
1130   int		  ulen,
1131   int		  size,
1132   int		* converted)
1133 {
1134   int  i;
1135   int  mask = 0;
1136   int  len;
1137   unsigned char c;
1138   ucs4_t wc;
1139   int  count = 0;
1140   int  _converted = 0;
1141   ucs4_t *u4str = (ucs4_t *)wstr;
1142   char *u8str = (char*)wstr;
1143 
1144   if (!ustr)
1145     return 0;
1146 
1147   if (charset == CP_UTF16)
1148     return _utf8ntoutf16 (ustr, wstr, ulen, size, converted);
1149 
1150   while ((_converted < ulen) && (count < size))
1151     {
1152       c = (unsigned char)*ustr;
1153       UTF8_COMPUTE (c, mask, len);
1154 
1155       if ((len == -1) || (_converted + len > ulen))
1156 	{
1157 	  if (converted)
1158 	    *converted = _converted;
1159 	  return count;
1160 	}
1161 
1162       if (charset == CP_UTF8)
1163         {
1164           for (i = 0; i < len; i++)
1165 	    *u8str++ = *ustr++;
1166 
1167 	  count += len;
1168           _converted += len;
1169         }
1170       else /* CP_UCS4 */
1171         {
1172           wc = c & mask;
1173           for (i = 1; i < len; i++)
1174 	    {
1175 	      if ((ustr[i] & 0xC0) != 0x80)
1176 	        {
1177 	          if (converted)
1178 		    *converted = _converted;
1179 	          return count;
1180 	        }
1181 	      wc <<= 6;
1182 	      wc |= (ustr[i] & 0x3F);
1183 	    }
1184 
1185           *u4str = (ucs4_t)wc;
1186           u4str++;
1187 
1188           ustr += len;
1189           count++;
1190           _converted += len;
1191         }
1192     }
1193 
1194   if (converted)
1195     *converted = _converted;
1196   return count;
1197 }
1198 
1199 /*
1200  *  size      - size of buffer for output string in symbols
1201  *  return    - length of output SQLWCHAR string in bytes
1202  */
1203 static size_t
_utf8towcx(IODBC_CHARSET charset,char * ustr,void * wstr,int size)1204 _utf8towcx (IODBC_CHARSET charset, char * ustr, void * wstr, int size)
1205 {
1206   if (!ustr)
1207     return 0;
1208 
1209   return _utf8ntowcx (charset, ustr, wstr, strlen(ustr), size, NULL);
1210 }
1211 
1212 
1213 /*
1214  *  ulen      - length of input *ustr string in bytes
1215  *  size      - size of buffer ( *wstr string) in symbols
1216  *  converted - number of converted bytes from *ustr
1217  *
1218  *  Return    - length of output wcs string
1219  */
1220 static size_t
utf8ntowcs(SQLCHAR * ustr,SQLWCHAR * wstr,int ulen,int size,int * converted)1221 utf8ntowcs (
1222   SQLCHAR	* ustr,
1223   SQLWCHAR	* wstr,
1224   int		  ulen,
1225   int		  size,
1226   int		* converted)
1227 {
1228   int i;
1229   int mask = 0;
1230   int len;
1231   SQLCHAR c;
1232   SQLWCHAR wc;
1233   int count = 0;
1234   int _converted = 0;
1235 
1236   if (!ustr)
1237     return 0;
1238 
1239   while ((_converted < ulen) && (count < size))
1240     {
1241       c = (SQLCHAR) *ustr;
1242       UTF8_COMPUTE (c, mask, len);
1243       if ((len == -1) || (_converted + len > ulen))
1244 	{
1245 	  if (converted)
1246 	    *converted = _converted;
1247 	  return count;
1248 	}
1249 
1250       wc = c & mask;
1251       for (i = 1; i < len; i++)
1252 	{
1253 	  if ((ustr[i] & 0xC0) != 0x80)
1254 	    {
1255 	      if (converted)
1256 		*converted = _converted;
1257 	      return count;
1258 	    }
1259 	  wc <<= 6;
1260 	  wc |= (ustr[i] & 0x3F);
1261 	}
1262       *wstr = wc;
1263       ustr += len;
1264       wstr++;
1265       count++;
1266       _converted += len;
1267     }
1268   if (converted)
1269     *converted = _converted;
1270   return count;
1271 }
1272 
1273 
1274 static SQLWCHAR *
strdup_U8toW(SQLCHAR * str)1275 strdup_U8toW (SQLCHAR * str)
1276 {
1277   SQLWCHAR *ret;
1278   int len;
1279 
1280   if (!str)
1281     return NULL;
1282 
1283   len = utf8_len (str, SQL_NTS);
1284   if ((ret = (SQLWCHAR *) malloc ((len + 1) * sizeof (SQLWCHAR))) == NULL)
1285     return NULL;
1286 
1287   len = utf8towcs ((char *)str, ret, len);
1288   ret[len] = L'\0';
1289 
1290   return ret;
1291 }
1292 
1293 
1294 SQLCHAR *
dm_SQL_WtoU8(SQLWCHAR * inStr,int size)1295 dm_SQL_WtoU8 (SQLWCHAR * inStr, int size)
1296 {
1297   SQLCHAR *outStr = NULL;
1298   int len;
1299 
1300   if (inStr == NULL)
1301     return NULL;
1302 
1303   if (size == SQL_NTS)
1304     {
1305       outStr = strdup_WtoU8 (inStr);
1306     }
1307   else
1308     {
1309       len = _calc_len_for_utf8 (CP_DEF, inStr, size);
1310       if ((outStr = (SQLCHAR *) malloc (len + 1)) != NULL)
1311 	{
1312 	  len = wcsntoutf8 (inStr, (char*)outStr, size, len, NULL);
1313 	  outStr[len] = '\0';
1314 	}
1315     }
1316 
1317   return outStr;
1318 }
1319 
1320 
1321 SQLWCHAR *
dm_SQL_U8toW(SQLCHAR * inStr,int size)1322 dm_SQL_U8toW (SQLCHAR * inStr, int size)
1323 {
1324   SQLWCHAR *outStr = NULL;
1325   int len;
1326 
1327   if (inStr == NULL)
1328     return NULL;
1329 
1330   if (size == SQL_NTS)
1331     {
1332       outStr = strdup_U8toW (inStr);
1333     }
1334   else
1335     {
1336       len = utf8_len (inStr, size);
1337       if ((outStr = (SQLWCHAR *) calloc (len + 1, sizeof (SQLWCHAR))) != NULL)
1338 	utf8ntowcs (inStr, outStr, size, len, NULL);
1339     }
1340 
1341   return outStr;
1342 }
1343 
1344 
1345 int
dm_StrCopyOut2_U8toW(SQLCHAR * inStr,SQLWCHAR * outStr,int size,WORD * result)1346 dm_StrCopyOut2_U8toW (
1347   SQLCHAR	* inStr,
1348   SQLWCHAR	* outStr,
1349   int		  size,
1350   WORD		* result)
1351 {
1352   int length;
1353 
1354   if (!inStr)
1355     return -1;
1356 
1357   length = utf8_len (inStr, SQL_NTS);
1358 
1359   if (result)
1360     *result = (SQLSMALLINT) length;
1361 
1362   if (!outStr)
1363     return 0;
1364 
1365   if (size >= length + 1)
1366     {
1367       length = utf8towcs ((char *)inStr, outStr, size);
1368       outStr[length] = L'\0';
1369       return 0;
1370     }
1371   if (size > 0)
1372     {
1373       length = utf8towcs ((char *)inStr, outStr, size - 1);
1374       outStr[length] = L'\0';
1375     }
1376   return -1;
1377 }
1378 
1379 
1380 static size_t
_WCSLEN(IODBC_CHARSET charset,void * str)1381 _WCSLEN(IODBC_CHARSET charset, void *str)
1382 {
1383   size_t len = 0;
1384   ucs4_t *u4str = (ucs4_t *)str;
1385   ucs2_t *u2str = (ucs2_t *)str;
1386 
1387   if (!str)
1388     return 0;
1389 
1390   switch(charset)
1391     {
1392     case CP_UTF8:
1393       return utf8_len((SQLCHAR *)str, SQL_NTS);
1394     case CP_UTF16:
1395       while (*u2str++ != 0)
1396         len++;
1397       break;
1398     case CP_UCS4:
1399       while (*u4str++ != 0)
1400         len++;
1401       break;
1402     }
1403   return len;
1404 }
1405 
1406 
1407 
1408 /*
1409  * ilen -  length of inStr in SQL Ind format
1410  * olen - size of outStr buffer in symbols
1411  * return length of copied data in symbols
1412  */
1413 static size_t
dm_U2toU4(ucs2_t * inStr,int ilen,ucs4_t * outStr,int olen)1414 dm_U2toU4(ucs2_t *inStr, int ilen, ucs4_t *outStr, int olen)
1415 {
1416   size_t n = 0;
1417   char *us = (char *) inStr;
1418   char *us_end = (char *)(inStr + ilen);
1419   ucs4_t wc;
1420   int count = 0;
1421 
1422   while(n < ilen)
1423     {
1424 #ifdef WORDS_BIGENDIAN
1425       wc = (ucs4_t) eh_decode_char__UTF16BE((__constcharptr *) &us, us_end);
1426 #else
1427       wc = (ucs4_t) eh_decode_char__UTF16LE((__constcharptr *) &us, us_end);
1428 #endif
1429       if (wc == UNICHAR_EOD || wc == UNICHAR_NO_DATA || wc == UNICHAR_BAD_ENCODING)
1430         break;
1431 
1432       if (count + 1 > olen)
1433         break;
1434 
1435       *outStr = wc;
1436       n++;
1437       outStr++;
1438       count ++;
1439     }
1440   return count;
1441 }
1442 
1443 
1444 
1445 static size_t
dm_U4toU2(ucs4_t * inStr,int ilen,ucs2_t * outStr,int olen)1446 dm_U4toU2(ucs4_t *inStr, int ilen, ucs2_t *outStr, int olen)
1447 {
1448   size_t n = 0;
1449   char *rc;
1450   char *us = (char*) outStr;
1451   char *us_end = (char*) (outStr + olen);
1452 
1453   while (n < ilen && us < us_end)
1454     {
1455 #ifdef WORDS_BIGENDIAN
1456       rc = eh_encode_char__UTF16BE (*inStr, us, us_end);
1457 #else
1458       rc = eh_encode_char__UTF16LE (*inStr, us, us_end);
1459 #endif
1460       if ((char *)UNICHAR_NO_ROOM == rc)
1461         break;
1462 
1463       us = rc;
1464       n++;
1465       inStr++;
1466 
1467       if (!*inStr)
1468 	break;
1469     }
1470   return (us - (char *)outStr) / sizeof(ucs2_t);
1471 }
1472 
1473 
1474 
1475 static size_t
dm_AtoU2(char * src,int ilen,ucs2_t * dest,int olen)1476 dm_AtoU2(char *src, int ilen, ucs2_t *dest, int olen)
1477 {
1478   size_t n = 0;
1479   wchar_t wc;
1480   char *rc;
1481   char *us = (char*) dest;
1482   char *us_end = (char*)(dest + olen);
1483   mbstate_t st;
1484 
1485   memset (&st, 0, sizeof (st));
1486 
1487   while (n < ilen && us < us_end)
1488     {
1489       size_t sz = mbrtowc (&wc, src, ilen - n, &st);
1490 
1491       if (((long) sz) > 0)
1492         {
1493           n += sz - 1;
1494           src += sz - 1;
1495         }
1496       else if (((long) sz) < 0)
1497         {
1498           wc = 0xFFFD;
1499         }
1500 
1501 #ifdef WORDS_BIGENDIAN
1502       rc = eh_encode_char__UTF16BE (wc, us, us_end);
1503 #else
1504       rc = eh_encode_char__UTF16LE (wc, us, us_end);
1505 #endif
1506       if ((char *)UNICHAR_NO_ROOM == rc)
1507         break;
1508 
1509       us = rc;
1510       n++;
1511       if (!*src)
1512 	break;
1513       src++;
1514     }
1515   return (us - (char *)dest) / sizeof(ucs2_t);
1516 }
1517 
1518 
1519 static size_t
dm_AtoU4(char * src,int ilen,ucs4_t * dest,size_t olen)1520 dm_AtoU4(char *src, int ilen, ucs4_t *dest, size_t olen)
1521 {
1522   size_t n = 0;
1523   wchar_t wc;
1524   ucs4_t *us = dest;
1525   int count = 0;
1526   mbstate_t st;
1527 
1528   memset (&st, 0, sizeof (st));
1529 
1530   while (n < ilen && count < olen)
1531     {
1532       size_t sz = mbrtowc (&wc, src, ilen - n, &st);
1533 
1534       if (((long) sz) > 0)
1535         {
1536           n += sz - 1;
1537           src += sz - 1;
1538         }
1539       else if (((long) sz) < 0)
1540         {
1541           wc = 0xFFFD;
1542         }
1543 
1544       *us = wc;
1545       n++;
1546       us++;
1547       count++;
1548       if (!*src)
1549 	break;
1550       src++;
1551     }
1552   return count;
1553 }
1554 
1555 
1556 static size_t
dm_AtoUW(char * src,int ilen,wchar_t * dest,size_t olen)1557 dm_AtoUW(char *src, int ilen, wchar_t *dest, size_t olen)
1558 {
1559   size_t n = 0;
1560   wchar_t wc;
1561   ucs4_t *us = dest;
1562   int count = 0;
1563   mbstate_t st;
1564 
1565   memset (&st, 0, sizeof (st));
1566 
1567   while (n < ilen && count < olen)
1568     {
1569       size_t sz = mbrtowc (&wc, src, ilen - n, &st);
1570 
1571       if (((long) sz) > 0)
1572         {
1573           n += sz - 1;
1574           src += sz - 1;
1575         }
1576       else if (((long) sz) < 0)
1577         {
1578           wc = 0xFFFD;
1579         }
1580 
1581       *us = wc;
1582       n++;
1583       us++;
1584       count++;
1585       if (!*src)
1586 	break;
1587       src++;
1588     }
1589   return count;
1590 }
1591 
1592 
1593 static size_t
dm_U2toA(ucs2_t * src,int ilen,char * dest,int olen)1594 dm_U2toA(ucs2_t *src, int ilen, char *dest, int olen)
1595 {
1596   size_t n = 0;
1597   char *us = (char *) src;
1598   char *us_end = (char*)(src + ilen);
1599   wchar_t wc;
1600   mbstate_t st;
1601 
1602   if (!*src)
1603     return 0;
1604 
1605   while (n < olen)
1606     {
1607       char temp[MB_CUR_MAX];
1608       size_t sz, sz_written = 0;
1609 #ifdef WORDS_BIGENDIAN
1610       wc = eh_decode_char__UTF16BE((__constcharptr *) &us, us_end);
1611 #else
1612       wc = eh_decode_char__UTF16LE((__constcharptr *) &us, us_end);
1613 #endif
1614       if (wc == UNICHAR_EOD || wc == UNICHAR_NO_DATA || wc == UNICHAR_BAD_ENCODING)
1615         break;
1616 
1617       memset (&st, 0, sizeof (st));
1618 
1619       sz = wcrtomb (temp, wc, &st);
1620       if (((long) sz) > 0)
1621 	{
1622 	  if (sz > olen - n)
1623 	    break;
1624 
1625 	  memcpy (dest, temp, sz);
1626 	  n += sz - 1;
1627 	  dest += sz - 1;
1628 	}
1629       else
1630 	*dest = '?';
1631 
1632       n++;
1633       dest++;
1634     }
1635   return n;
1636 }
1637 
1638 
1639 static size_t
dm_U4toA(ucs4_t * src,int ilen,char * dest,int olen)1640 dm_U4toA(ucs4_t *src, int ilen, char *dest, int olen)
1641 {
1642   int n = 0;
1643   wchar_t wc;
1644   int count = 0;
1645   mbstate_t st;
1646 
1647   if (!*src)
1648     return 0;
1649 
1650   while (n < ilen && count < olen)
1651     {
1652       char temp[MB_CUR_MAX];
1653       size_t sz, sz_written = 0;
1654 
1655       memset (&st, 0, sizeof (st));
1656 
1657       wc = *src;
1658       sz = wcrtomb (temp, wc, &st);
1659 
1660       if (((long) sz) > 0)
1661 	{
1662 	  if (sz > olen - count)
1663 	    break;
1664 
1665 	  memcpy (dest, temp, sz);
1666 	  count += sz - 1;
1667 	  dest += sz - 1;
1668 	}
1669       else
1670 	*dest = '?';
1671 
1672       src++;
1673       count++;
1674       n++;
1675       dest++;
1676     }
1677   return n;
1678 }
1679 
1680 
1681 
1682 static size_t
dm_UWtoA(wchar_t * src,int ilen,char * dest,int olen)1683 dm_UWtoA(wchar_t *src, int ilen, char *dest, int olen)
1684 {
1685   int n = 0;
1686   wchar_t wc;
1687   int count = 0;
1688   mbstate_t st;
1689 
1690   if (!*src)
1691     return 0;
1692 
1693   while (n < ilen && count < olen)
1694     {
1695       char temp[MB_CUR_MAX];
1696       size_t sz, sz_written = 0;
1697 
1698       memset (&st, 0, sizeof (st));
1699 
1700       wc = *src;
1701       sz = wcrtomb (temp, wc, &st);
1702 
1703       if (((long) sz) > 0)
1704 	{
1705 	  if (sz > olen - count)
1706 	    break;
1707 
1708 	  memcpy (dest, temp, sz);
1709 	  count += sz - 1;
1710 	  dest += sz - 1;
1711 	}
1712       else
1713 	*dest = '?';
1714 
1715       src++;
1716       count++;
1717       n++;
1718       dest++;
1719     }
1720   return n;
1721 }
1722 
1723 
1724 
1725 /*
1726  * len -  length of inStr in SQL Ind format
1727  * size - size of outStr buffer in bytes
1728  * return length of copied data in bytes
1729  */
1730 int
dm_conv_W2W(void * inStr,int len,void * outStr,int size,IODBC_CHARSET icharset,IODBC_CHARSET ocharset)1731 dm_conv_W2W(void *inStr, int len, void *outStr, int size,
1732 	IODBC_CHARSET icharset, IODBC_CHARSET ocharset)
1733 {
1734   int count = 0;
1735   int o_wchar_size = _WCHARSIZE(ocharset);
1736 
1737   size /= o_wchar_size;
1738 
1739   if (icharset == CP_UTF8)
1740     {
1741       if (len == SQL_NTS)
1742         len = strlen((char*)inStr);
1743 
1744       count = _utf8ntowcx(ocharset, (char*)inStr, outStr, len, size, NULL);
1745       return count * o_wchar_size;
1746     }
1747   else if (ocharset == CP_UTF8)
1748     {
1749       if (len == SQL_NTS)
1750         len = (icharset==CP_UTF8)?strlen((char*)inStr):_WCSLEN(icharset, inStr);
1751 
1752       return _wcxntoutf8(icharset, inStr, (char*)outStr, len, size, NULL);
1753     }
1754   else
1755     {
1756       if (len == SQL_NTS)
1757         len = _WCSLEN(icharset, inStr);
1758 
1759       if (icharset == CP_UTF16)
1760         {
1761           if (ocharset == CP_UCS4)
1762             {
1763               count = dm_U2toU4((ucs2_t *)inStr, len, (ucs4_t *)outStr, size);
1764               return count * o_wchar_size;
1765             }
1766           else
1767             {
1768               ucs2_t *u2i = (ucs2_t *) inStr;
1769               ucs2_t *u2o = (ucs2_t *) outStr;
1770               while(len > 0 && count < size)
1771                 {
1772                   *u2o = *u2i;
1773                    u2o++;
1774                    u2i++;
1775                    len--;
1776                    count++;
1777                 }
1778               return count * o_wchar_size;
1779             }
1780         }
1781       else /* CP_UCS4 */
1782         {
1783           if (ocharset == CP_UTF16)
1784             {
1785               count = dm_U4toU2((ucs4_t *)inStr, len, (ucs2_t *)outStr, size);
1786               return count * o_wchar_size;
1787             }
1788           else
1789             {
1790               ucs4_t *u4i = (ucs4_t *) inStr;
1791               ucs4_t *u4o = (ucs4_t *) outStr;
1792               while(len > 0 && count < size)
1793                 {
1794                   *u4o = *u4i;
1795                    u4o++;
1796                    u4i++;
1797                    len--;
1798                    count++;
1799                 }
1800               return count * o_wchar_size;
1801             }
1802         }
1803     }
1804 }
1805 
1806 
1807 /*
1808  * len -  length of inStr in SQL Ind format
1809  * size - size of buffer for output string in bytes
1810  * return length of copied data in bytes
1811  */
1812 int
dm_conv_W2A(void * inStr,int inLen,char * outStr,int size,IODBC_CHARSET charset)1813 dm_conv_W2A(void *inStr, int inLen, char *outStr, int size,
1814 	IODBC_CHARSET charset)
1815 {
1816   SQLWCHAR wc;
1817   int count = 0;
1818 
1819   if (inLen == SQL_NTS)
1820     {
1821       inLen = (charset == CP_UTF8) ? strlen((char*)inStr)
1822                                    : _WCSLEN(charset, inStr);
1823     }
1824 
1825   if (size > 0)
1826     {
1827       if (charset == CP_UTF8)
1828         {
1829           SQLCHAR *u8 = (SQLCHAR *)inStr;
1830           SQLCHAR c;
1831           int len, mask, i;
1832           char temp[MB_CUR_MAX];
1833           mbstate_t st;
1834           size_t rc;
1835 
1836           while((c = *u8) && size > 0 && inLen > 0)
1837             {
1838               UTF8_COMPUTE (c, mask, len);
1839               if (len == -1)
1840                 return count;
1841 
1842               wc = c & mask;
1843               for(i = 1; i < len; i++)
1844                 {
1845                   if ((u8[i] & 0xC0) != 0x80)
1846                     return count;
1847                   wc <<= 6;
1848                   wc |= (u8[i] & 0x3F);
1849                 }
1850 
1851               memset (&st, 0, sizeof (st));
1852               rc = wcrtomb (temp, wc, &st);
1853               if (((ssize_t)rc) > 0)
1854                 {
1855                   rc = MIN(rc, MB_CUR_MAX);
1856                   if (rc > size)
1857                     break;
1858 
1859                   memcpy(outStr, temp, rc);
1860                   size -= rc -1;
1861                   outStr += rc - 1;
1862                   count += rc - 1;
1863                 }
1864               else if (rc == 0)
1865                 {
1866                   *outStr = 0;
1867                 }
1868               else
1869                 {
1870                   *outStr = '?';
1871                 }
1872 
1873               size --;
1874               outStr ++;
1875               count ++;
1876 
1877               u8 += len;
1878               inLen -= len;
1879             }
1880         }
1881       else if (charset == CP_UTF16)
1882         {
1883           count = dm_U2toA((ucs2_t *)inStr, inLen, outStr, size);
1884         }
1885       else if (charset == CP_UCS4)
1886         {
1887           count = dm_U4toA((ucs4_t *)inStr, inLen, outStr, size);
1888         }
1889     }
1890   return count;
1891 }
1892 
1893 
1894 /*
1895  * len -  length of inStr in SQL Ind format
1896  * size - size of buffer for output string in bytes
1897  * return length of copied data in bytes
1898  */
1899 int
dm_conv_A2W(char * inStr,int inLen,void * outStr,int size,IODBC_CHARSET charset)1900 dm_conv_A2W(char *inStr, int inLen, void *outStr, int size,
1901 	IODBC_CHARSET charset)
1902 {
1903   SQLWCHAR wc;
1904   int count = 0;
1905   int o_wchar_size = _WCHARSIZE(charset);
1906 
1907   if (inLen == SQL_NTS)
1908     inLen = strlen(inStr);
1909 
1910   if (size > 0)
1911     {
1912       if (charset == CP_UTF8)
1913         {
1914           SQLCHAR *u8 = (SQLCHAR*)outStr;
1915           int len,first,i;
1916           mbstate_t st;
1917 
1918           memset (&st, 0, sizeof (st));
1919 
1920           while(*inStr && size>0 && inLen > 0)
1921             {
1922               size_t rc;
1923               rc = mbrtowc (&wc, inStr, (size_t)inLen, &st);
1924               if (((ssize_t)rc) > 0)
1925                 {
1926                   inLen -= rc - 1;
1927                   inStr += rc - 1;
1928                 }
1929               else if (((ssize_t)rc) < 0)
1930                 {
1931                   wc = 0xFFFD;
1932                 }
1933 
1934               CONV_TO_UTF8(wc, len, first);
1935               for(i = len-1; i > 0; --i)
1936                 {
1937                   u8[i] = (wc & 0x3F) | 0x80;
1938                   wc >>= 6;
1939                 }
1940               u8[0] = wc | first;
1941               u8 += len;
1942               size -= len;
1943               count += len;
1944               inStr++;
1945               inLen--;
1946             }
1947         }
1948       else if (charset == CP_UTF16)
1949         {
1950           count = dm_AtoU2(inStr, inLen, (ucs2_t *)outStr, size/o_wchar_size);
1951           count *= o_wchar_size;
1952         }
1953       else if (charset == CP_UCS4)
1954         {
1955           count = dm_AtoU4(inStr, inLen, (ucs4_t *)outStr, size/o_wchar_size);
1956           count *= o_wchar_size;
1957         }
1958     }
1959   return count;
1960 }
1961 
1962 
1963 static void
_SetWCharAt(IODBC_CHARSET charset,void * str,int pos,int ch)1964 _SetWCharAt(IODBC_CHARSET charset, void *str, int pos, int ch)
1965 {
1966   ucs4_t *u4 = (ucs4_t *)str;
1967   ucs2_t *u2 = (ucs2_t *)str;
1968 
1969   if (!str)
1970     return;
1971 
1972   switch(charset)
1973     {
1974     case CP_UTF8:
1975       {
1976         int i=0;
1977         SQLCHAR *u8str = (SQLCHAR*)str;
1978         while(i < pos)
1979         {
1980           int mask, len;
1981           UTF8_COMPUTE(*u8str, mask, len);
1982           if (len == -1)
1983             break;
1984           u8str += len;
1985           i++;
1986         }
1987         *u8str = (SQLCHAR)ch;
1988       }
1989       break;
1990     case CP_UTF16: u2[pos] = (ucs4_t)ch; break;
1991     case CP_UCS4: u4[pos] = (ucs4_t)ch; break;
1992     }
1993 }
1994 
1995 
1996 void
DM_strcpy_U8toW(DM_CONV * conv,void * dest,SQLCHAR * sour)1997 DM_strcpy_U8toW (DM_CONV *conv, void *dest, SQLCHAR *sour)
1998 {
1999   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2000   int len;
2001 
2002   if (!sour)
2003     return;
2004 
2005   if (charset == CP_UTF16 || charset == CP_UCS4)
2006     {
2007       len = utf8_len(sour, SQL_NTS) * _WCHARSIZE(charset);
2008       _utf8towcx(charset, (char *)sour, dest, len);
2009     }
2010   else
2011     strcpy(dest, (char *)sour);
2012 }
2013 
2014 
2015 size_t
DRV_WCHARSIZE(DM_CONV * conv)2016 DRV_WCHARSIZE(DM_CONV *conv)
2017 {
2018   IODBC_CHARSET charset = (conv) ? conv->drv_cp : CP_DEF;
2019   return _WCHARSIZE(charset);
2020 }
2021 
2022 
2023 size_t
DM_WCHARSIZE(DM_CONV * conv)2024 DM_WCHARSIZE(DM_CONV *conv)
2025 {
2026   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2027   return _WCHARSIZE(charset);
2028 }
2029 
2030 
2031 size_t
DRV_WCHARSIZE_ALLOC(DM_CONV * conv)2032 DRV_WCHARSIZE_ALLOC(DM_CONV *conv)
2033 {
2034   IODBC_CHARSET charset = (conv) ? conv->drv_cp : CP_DEF;
2035   return _WCHARSIZE_ALLOC(charset);
2036 }
2037 
2038 
2039 size_t
DM_WCHARSIZE_ALLOC(DM_CONV * conv)2040 DM_WCHARSIZE_ALLOC(DM_CONV *conv)
2041 {
2042   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2043   return _WCHARSIZE_ALLOC(charset);
2044 }
2045 
2046 void *
DM_A2W(DM_CONV * conv,SQLCHAR * inStr,int size)2047 DM_A2W(DM_CONV *conv, SQLCHAR * inStr, int size)
2048 {
2049   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2050   SQLWCHAR *outStr = NULL;
2051   ssize_t len;
2052 
2053   if (size == SQL_NTS)
2054     len = strlen((char *) inStr);
2055   else
2056     len = size;
2057 
2058   if (len < 0)
2059     return NULL;
2060 
2061   outStr = (SQLWCHAR *) calloc(len + 1, DM_WCHARSIZE_ALLOC(conv));
2062   if (!outStr)
2063     return NULL;
2064 
2065   dm_conv_A2W((char *)inStr, size, outStr, len*DM_WCHARSIZE_ALLOC(conv), charset);
2066   return outStr;
2067 }
2068 
2069 
2070 static SQLCHAR *
__W2A(IODBC_CHARSET charset,void * inStr,int size)2071 __W2A(IODBC_CHARSET charset, void * inStr, int size)
2072 {
2073   SQLCHAR *outStr = NULL;
2074   ssize_t len;
2075 
2076   if (size == SQL_NTS)
2077     len = _WCSLEN(charset, inStr);
2078   else
2079     len = size;
2080 
2081   if (len < 0)
2082     return NULL;
2083 
2084   outStr = (SQLCHAR *) calloc (len * MB_CUR_MAX + 1, 1);
2085   if (!outStr)
2086     return NULL;
2087 
2088   dm_conv_W2A(inStr, size, (char *)outStr, len, charset);
2089   return outStr;
2090 }
2091 
2092 SQLCHAR *
DM_W2A(DM_CONV * conv,void * inStr,int size)2093 DM_W2A(DM_CONV *conv, void * inStr, int size)
2094 {
2095   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2096   return __W2A(charset, inStr, size);
2097 }
2098 
2099 SQLCHAR *
DRV_W2A(DM_CONV * conv,void * inStr,int size)2100 DRV_W2A(DM_CONV *conv, void * inStr, int size)
2101 {
2102   IODBC_CHARSET charset = (conv) ? conv->drv_cp : CP_DEF;
2103   return __W2A(charset, inStr, size);
2104 }
2105 
2106 void
DM_SetWCharAt(DM_CONV * conv,void * str,int pos,int ch)2107 DM_SetWCharAt(DM_CONV *conv, void *str, int pos, int ch)
2108 {
2109   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2110   _SetWCharAt(charset, str, pos, ch);
2111 }
2112 
2113 
2114 void
DRV_SetWCharAt(DM_CONV * conv,void * str,int pos,int ch)2115 DRV_SetWCharAt(DM_CONV *conv, void *str, int pos, int ch)
2116 {
2117   IODBC_CHARSET charset = (conv) ? conv->drv_cp : CP_DEF;
2118   _SetWCharAt(charset, str, pos, ch);
2119 }
2120 
2121 
2122 SQLWCHAR
DM_GetWCharAt(DM_CONV * conv,void * str,int pos)2123 DM_GetWCharAt(DM_CONV *conv, void *str, int pos)
2124 {
2125   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2126   ucs4_t *u4 = (ucs4_t *)str;
2127   ucs2_t *u2 = (ucs2_t *)str;
2128 
2129   if (!str)
2130     return 0;
2131 
2132   switch(charset)
2133     {
2134     case CP_UTF8:
2135       {
2136         int mask, len, i=0;
2137         SQLWCHAR wc = 0;
2138         SQLCHAR *u8str = (SQLCHAR*)str;
2139         while(i < pos)
2140         {
2141           UTF8_COMPUTE(*u8str, mask, len);
2142           if (len == -1)
2143             break;
2144           u8str += len;
2145           i++;
2146         }
2147         UTF8_COMPUTE(*u8str, mask, len);
2148         wc = (*u8str)&mask;
2149         for(i=1; i < len; i++)
2150           {
2151             if ((u8str[i] & 0xC0) != 0x80)
2152               return 0;
2153             wc <<= 6;
2154             wc |= (u8str[i] & 0x3F);
2155           }
2156         return wc;
2157       }
2158     case CP_UTF16: return (SQLWCHAR)u2[pos];
2159     case CP_UCS4: return (SQLWCHAR)u4[pos];
2160     }
2161 }
2162 
2163 
2164 static void *
_WCSCPY(IODBC_CHARSET charset,void * dest,void * sour)2165 _WCSCPY(IODBC_CHARSET charset, void *dest, void *sour)
2166 {
2167   ucs4_t *u4dst = (ucs4_t *)dest;
2168   ucs2_t *u2dst = (ucs2_t *)dest;
2169   ucs4_t *u4src = (ucs4_t *)sour;
2170   ucs2_t *u2src = (ucs2_t *)sour;
2171 
2172   switch(charset)
2173     {
2174     case CP_UTF8:
2175       strcpy((char*)dest, (char*)sour);
2176       break;
2177     case CP_UTF16:
2178       while ((*u2dst++ = *u2src++) != 0)
2179         ;
2180       *u2dst = 0;
2181       break;
2182     case CP_UCS4:
2183       while ((*u4dst++ = *u4src++) != 0)
2184         ;
2185       *u4dst = 0;
2186       break;
2187     }
2188   return dest;
2189 }
2190 
2191 
2192 static void *
_WCSNCPY(IODBC_CHARSET charset,void * dest,void * sour,size_t count)2193 _WCSNCPY(IODBC_CHARSET charset, void *dest, void *sour, size_t count)
2194 {
2195   size_t len = 0;
2196   ucs4_t *u4dst = (ucs4_t *)dest;
2197   ucs2_t *u2dst = (ucs2_t *)dest;
2198   ucs4_t *u4src = (ucs4_t *)sour;
2199   ucs2_t *u2src = (ucs2_t *)sour;
2200 
2201   switch(charset)
2202     {
2203     case CP_UTF8:
2204       strncpy((char*)dest, (char*)sour, count);
2205       break;
2206     case CP_UTF16:
2207       while (len < count && (*u2dst++ = *u2src++) != 0)
2208         len++;
2209       if (len < count)
2210         *u2dst = 0;
2211       break;
2212     case CP_UCS4:
2213       while (len < count && (*u4dst++ = *u4src++) != 0)
2214         len++;
2215       if (len < count)
2216         *u4dst = 0;
2217       break;
2218     }
2219   return dest;
2220 }
2221 
2222 
2223 void *
DM_WCSCPY(DM_CONV * conv,void * dest,void * sour)2224 DM_WCSCPY(DM_CONV *conv, void *dest, void *sour)
2225 {
2226   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2227   return _WCSCPY(charset, dest, sour);
2228 }
2229 
2230 
2231 void *
DM_WCSNCPY(DM_CONV * conv,void * dest,void * sour,size_t count)2232 DM_WCSNCPY(DM_CONV *conv, void *dest, void *sour, size_t count)
2233 {
2234   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2235   return _WCSNCPY(charset, dest, sour, count);
2236 }
2237 
2238 
2239 void *
DRV_WCSNCPY(DM_CONV * conv,void * dest,void * sour,size_t count)2240 DRV_WCSNCPY(DM_CONV *conv, void *dest, void *sour, size_t count)
2241 {
2242   IODBC_CHARSET charset = (conv) ? conv->drv_cp : CP_DEF;
2243   return _WCSNCPY(charset, dest, sour, count);
2244 }
2245 
2246 
2247 size_t
DM_WCSLEN(DM_CONV * conv,void * str)2248 DM_WCSLEN(DM_CONV *conv, void *str)
2249 {
2250   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2251   return _WCSLEN(charset, str);
2252 }
2253 
2254 
2255 size_t
DRV_WCSLEN(DM_CONV * conv,void * str)2256 DRV_WCSLEN(DM_CONV *conv, void *str)
2257 {
2258   IODBC_CHARSET charset = (conv) ? conv->drv_cp : CP_DEF;
2259   return _WCSLEN(charset, str);
2260 }
2261 
2262 
2263 static SQLCHAR *
__WtoU8(IODBC_CHARSET charset,void * inStr,int size)2264 __WtoU8(IODBC_CHARSET charset, void *inStr, int size)
2265 {
2266   SQLCHAR *outStr = NULL;
2267   int len;
2268 
2269   if (inStr == NULL)
2270     return NULL;
2271 
2272   len = _calc_len_for_utf8(charset, inStr, size);
2273   if (!(outStr = (SQLCHAR *) calloc (len + 1, sizeof(char))))
2274     return NULL;
2275 
2276   if (size == SQL_NTS)
2277     _wcxtoutf8 (charset, inStr, (char *)outStr, len);
2278   else
2279     _wcxntoutf8 (charset, inStr, (char *)outStr, size, len, NULL);
2280 
2281   return outStr;
2282 }
2283 
2284 
2285 SQLCHAR *
DM_WtoU8(DM_CONV * conv,void * inStr,int size)2286 DM_WtoU8(DM_CONV *conv, void *inStr, int size)
2287 {
2288   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2289   return __WtoU8(charset, inStr, size);
2290 }
2291 
2292 
2293 SQLCHAR *
DRV_WtoU8(DM_CONV * conv,void * inStr,int size)2294 DRV_WtoU8(DM_CONV *conv, void *inStr, int size)
2295 {
2296   IODBC_CHARSET charset = (conv) ? conv->drv_cp : CP_DEF;
2297   return __WtoU8(charset, inStr, size);
2298 }
2299 
2300 
2301 void *
DM_U8toW(DM_CONV * conv,SQLCHAR * inStr,int size)2302 DM_U8toW(DM_CONV *conv, SQLCHAR *inStr, int size)
2303 {
2304   IODBC_CHARSET charset = (conv) ? conv->dm_cp : CP_DEF;
2305   void *outStr = NULL;
2306   int  len = 0;
2307 
2308   if (inStr == NULL)
2309     return NULL;
2310 
2311   len = utf8_len (inStr, size);
2312   outStr = (void *) calloc (len + 1, _WCHARSIZE_ALLOC(charset));
2313 
2314   if (size == SQL_NTS)
2315     _utf8towcx(charset, (char *)inStr, outStr, len);
2316   else
2317     _utf8ntowcx(charset, (char *)inStr, outStr, size, len, NULL);
2318 
2319   return outStr;
2320 }
2321 
2322 
2323 /*  drv => dm
2324  *
2325  * size - size of outStr in bytes
2326  * result - length in symbols
2327  * copied - count of copied in bytes
2328  */
2329 int
dm_StrCopyOut2_A2W_d2m(DM_CONV * conv,SQLCHAR * inStr,void * outStr,int size,SQLSMALLINT * result,int * copied)2330 dm_StrCopyOut2_A2W_d2m (DM_CONV *conv, SQLCHAR *inStr,
2331 		void *outStr, int size, SQLSMALLINT *result, int *copied)
2332 {
2333   IODBC_CHARSET o_charset = (conv) ? conv->dm_cp : CP_DEF;
2334   int length, count;
2335   int ret = 0;
2336 
2337   if (!inStr)
2338     return -1;
2339 
2340   length = strlen ((char *) inStr);
2341 
2342   if (result)
2343     *result = (SQLSMALLINT) length;
2344 
2345   if (!outStr)
2346     return 0;
2347 
2348   size -= DM_WCHARSIZE(conv);
2349 
2350   if (size <= 0)
2351     return -1;
2352 
2353   count = dm_conv_A2W((char *)inStr, SQL_NTS, outStr, size, o_charset);
2354 
2355   if (o_charset == CP_UTF16 || o_charset == CP_UCS4)
2356     _SetWCharAt(o_charset, outStr, count/_WCHARSIZE(o_charset), 0);
2357   else
2358     *(char*)(outStr + count) = 0;
2359 
2360   if (_WCSLEN(o_charset, outStr) < length)
2361     ret = -1;
2362 
2363   if (copied)
2364     *copied = count;
2365 
2366   return ret;
2367 }
2368 
2369 
2370 /* drv => dm */
2371 int
dm_StrCopyOut2_W2A_d2m(DM_CONV * conv,void * inStr,SQLCHAR * outStr,int size,SQLSMALLINT * result,int * copied)2372 dm_StrCopyOut2_W2A_d2m (DM_CONV *conv, void *inStr,
2373 		SQLCHAR *outStr, int size, SQLSMALLINT *result, int *copied)
2374 {
2375   IODBC_CHARSET i_charset = (conv) ? conv->drv_cp : CP_DEF;
2376   int length, count;
2377   int ret = 0;
2378 
2379   if (!inStr)
2380     return -1;
2381 
2382   length = _WCSLEN(i_charset, inStr);
2383 
2384   if (result)
2385     *result = (SQLSMALLINT) length;
2386 
2387   if (!outStr)
2388     return 0;
2389 
2390   size--;
2391 
2392   if (size < 0)
2393     return -1;
2394 
2395   count = dm_conv_W2A(inStr, SQL_NTS, (char *)outStr, size, i_charset);
2396   outStr[count] = '\0';
2397 
2398   if (count < length)
2399     ret = -1;
2400 
2401   if (copied)
2402     *copied = count;
2403 
2404   return ret;
2405 }
2406 
2407 
2408 /* dm => drv */
2409 int
dm_StrCopyOut2_W2A_m2d(DM_CONV * conv,void * inStr,SQLCHAR * outStr,int size,SQLSMALLINT * result,int * copied)2410 dm_StrCopyOut2_W2A_m2d (DM_CONV *conv, void *inStr,
2411 		SQLCHAR *outStr, int size, SQLSMALLINT *result, int *copied)
2412 {
2413   IODBC_CHARSET i_charset = (conv) ? conv->dm_cp : CP_DEF;
2414   int length, count;
2415   int ret = 0;
2416 
2417   if (!inStr)
2418     return -1;
2419 
2420   length = _WCSLEN(i_charset, inStr);
2421 
2422   if (result)
2423     *result = (SQLSMALLINT) length;
2424 
2425   if (!outStr)
2426     return 0;
2427 
2428   size--;
2429 
2430   if (size < 0)
2431     return -1;
2432 
2433   count = dm_conv_W2A(inStr, SQL_NTS, (char *)outStr, size, i_charset);
2434   outStr[count] = '\0';
2435 
2436   if (count < length)
2437     ret = -1;
2438 
2439   if (copied)
2440     *copied = count;
2441 
2442   return ret;
2443 }
2444 
2445 
2446 /* drv => dm
2447  *
2448  * size - size of outStr in bytes
2449  * result - length in symbols
2450  * copied - count of copied in bytes
2451 */
2452 int
dm_StrCopyOut2_U8toW_d2m(DM_CONV * conv,SQLCHAR * inStr,void * outStr,int size,SQLSMALLINT * result,int * copied)2453 dm_StrCopyOut2_U8toW_d2m (DM_CONV *conv, SQLCHAR *inStr,
2454 		void *outStr, int size, SQLSMALLINT *result, int *copied)
2455 {
2456   IODBC_CHARSET o_charset = (conv) ? conv->dm_cp : CP_DEF;
2457   int length;
2458   int ret = 0;
2459   int count = 0;
2460 
2461   if (!inStr)
2462     return -1;
2463 
2464   length = utf8_len ((SQLCHAR *) inStr, SQL_NTS);
2465 
2466   if (result)
2467     *result = (SQLSMALLINT) length;
2468 
2469   if (!outStr)
2470     return 0;
2471 
2472   size -= _WCHARSIZE(o_charset);
2473 
2474   if (size < 0)
2475     return -1;
2476 
2477   count = dm_conv_W2W(inStr, SQL_NTS, outStr, size, CP_UTF8, o_charset);
2478 
2479   if (o_charset == CP_UTF16 || o_charset == CP_UCS4)
2480     _SetWCharAt(o_charset, outStr, count/_WCHARSIZE(o_charset), 0);
2481   else
2482     *(char*)(outStr + count) = 0;
2483 
2484   if (_WCSLEN(o_charset, outStr) < length)
2485     ret = -1;
2486 
2487   if (copied)
2488     *copied = count;
2489 
2490   return ret;
2491 }
2492 
2493 
2494 
2495 /* drv => dm
2496  *
2497  * size - size of outStr in bytes
2498  * result - length in symbols
2499  * copied - count of copied in bytes
2500 */
2501 int
dm_StrCopyOut2_W2W_d2m(DM_CONV * conv,void * inStr,void * outStr,int size,SQLSMALLINT * result,int * copied)2502 dm_StrCopyOut2_W2W_d2m (DM_CONV *conv, void *inStr,
2503 		void *outStr, int size, SQLSMALLINT *result, int *copied)
2504 {
2505   IODBC_CHARSET o_charset = (conv) ? conv->dm_cp : CP_DEF;
2506   IODBC_CHARSET i_charset = (conv) ? conv->drv_cp : CP_DEF;
2507   int length;
2508   int ret = 0;
2509   int count = 0;
2510 
2511   if (!inStr)
2512     return -1;
2513 
2514   length = _WCSLEN(i_charset, inStr);
2515 
2516   if (result)
2517     *result = (SQLSMALLINT) length;
2518 
2519   if (!outStr)
2520     return 0;
2521 
2522   size -= _WCHARSIZE(o_charset);
2523 
2524   if (size <= 0)
2525     return -1;
2526 
2527   count = dm_conv_W2W(inStr, SQL_NTS, outStr, size, i_charset, o_charset);
2528 
2529   if (o_charset == CP_UTF16 || o_charset == CP_UCS4)
2530     _SetWCharAt(o_charset, outStr, count/_WCHARSIZE(o_charset), 0);
2531   else
2532     *(char*)(outStr + count) = 0;
2533 
2534   if (_WCSLEN(o_charset, outStr) < length)
2535     ret = -1;
2536 
2537   if (copied)
2538     *copied = count;
2539 
2540   return ret;
2541 }
2542 
2543 
2544 /* dm => drv
2545  *
2546  * size - size of outStr in bytes
2547  * result - length in symbols
2548  * copied - count of copied in bytes
2549 */
2550 int
dm_StrCopyOut2_W2W_m2d(DM_CONV * conv,void * inStr,void * outStr,int size,SQLSMALLINT * result,int * copied)2551 dm_StrCopyOut2_W2W_m2d (DM_CONV *conv, void *inStr,
2552 		void *outStr, int size, SQLSMALLINT *result, int *copied)
2553 {
2554   IODBC_CHARSET o_charset = (conv) ? conv->drv_cp : CP_DEF;
2555   IODBC_CHARSET i_charset = (conv) ? conv->dm_cp : CP_DEF;
2556   int length;
2557   int ret = 0;
2558   int count = 0;
2559 
2560   if (!inStr)
2561     return -1;
2562 
2563   length = _WCSLEN(i_charset, inStr);
2564 
2565   if (result)
2566     *result = (SQLSMALLINT) length;
2567 
2568   if (!outStr)
2569     return 0;
2570 
2571   size -= _WCHARSIZE(o_charset);
2572 
2573   if (size <= 0)
2574     return -1;
2575 
2576   count = dm_conv_W2W(inStr, SQL_NTS, outStr, size, i_charset, o_charset);
2577 
2578   if (o_charset == CP_UTF16 || o_charset == CP_UCS4)
2579     _SetWCharAt(o_charset, outStr, count/_WCHARSIZE(o_charset), 0);
2580   else
2581     *(char*)(outStr + count) = 0;
2582 
2583   if (_WCSLEN(o_charset, outStr) < length)
2584     ret = -1;
2585 
2586   if (copied)
2587     *copied = count;
2588 
2589   return ret;
2590 }
2591 
2592 
2593 /* drv => dm */
2594 void *
conv_text_d2m(DM_CONV * conv,void * inStr,int size,CONV_DIRECT direct)2595 conv_text_d2m(DM_CONV *conv, void *inStr, int size, CONV_DIRECT direct)
2596 {
2597   IODBC_CHARSET m_charset = (conv) ? conv->dm_cp : CP_DEF;
2598   IODBC_CHARSET d_charset = (conv) ? conv->drv_cp : CP_DEF;
2599   void *outStr = NULL;
2600   int len;
2601 
2602   if (inStr == NULL)
2603     return NULL;
2604 
2605   if (size == SQL_NTS)
2606     {
2607       if (direct == CD_W2A || direct == CD_W2W)
2608         len = DRV_WCSLEN(conv, inStr);
2609       else
2610         len = strlen ((char *)inStr);
2611     }
2612   else
2613     len = size;
2614 
2615   if (len < 0)
2616     return NULL;
2617 
2618   if (direct == CD_W2A)
2619     outStr = calloc (len * MB_CUR_MAX + 1, 1);
2620   else
2621     outStr = calloc(len + 1, DM_WCHARSIZE_ALLOC(conv));
2622 
2623   if (outStr)
2624     {
2625       if (direct == CD_A2W)
2626         {
2627           dm_conv_A2W((char *)inStr, size, outStr,
2628 		len*DM_WCHARSIZE_ALLOC(conv),m_charset);
2629         }
2630       else if (direct == CD_W2A)
2631         {
2632           dm_conv_W2A(inStr, size, (char *)outStr, len, d_charset);
2633         }
2634       else /* CD_W2W */
2635         {
2636           dm_conv_W2W(inStr, size, outStr, len*DM_WCHARSIZE_ALLOC(conv),
2637 		d_charset, m_charset);
2638         }
2639     }
2640 
2641   return outStr;
2642 }
2643 
2644 
2645 
2646 /* dm => drv */
2647 void *
conv_text_m2d(DM_CONV * conv,void * inStr,int size,CONV_DIRECT direct)2648 conv_text_m2d(DM_CONV *conv, void *inStr, int size, CONV_DIRECT direct)
2649 {
2650   IODBC_CHARSET m_charset = (conv) ? conv->dm_cp : CP_DEF;
2651   IODBC_CHARSET d_charset = (conv) ? conv->drv_cp : CP_DEF;
2652   void *outStr = NULL;
2653   int len;
2654 
2655   if (inStr == NULL)
2656     return NULL;
2657 
2658   if (size == SQL_NTS)
2659     {
2660       if (direct == CD_W2A || direct == CD_W2W)
2661         len = DM_WCSLEN(conv, inStr);
2662       else
2663         len = strlen ((char *)inStr);
2664     }
2665   else
2666     len = size;
2667 
2668   if (len < 0)
2669     return NULL;
2670 
2671   if (direct == CD_W2A)
2672     outStr = calloc (len * MB_CUR_MAX + 1, 1);
2673   else
2674     outStr = calloc(len + 1, DRV_WCHARSIZE_ALLOC(conv));
2675 
2676   if (outStr)
2677     {
2678       if (direct == CD_A2W)
2679         {
2680           dm_conv_A2W((char *)inStr, size, outStr,
2681 		len*DRV_WCHARSIZE_ALLOC(conv), d_charset);
2682         }
2683       else if (direct == CD_W2A)
2684         {
2685           dm_conv_W2A(inStr, size, (char *)outStr, len, m_charset);
2686         }
2687       else /* CD_W2W */
2688         {
2689           dm_conv_W2W(inStr, size, outStr, len*DRV_WCHARSIZE_ALLOC(conv),
2690 			m_charset, d_charset);
2691         }
2692     }
2693 
2694   return outStr;
2695 }
2696 
2697 
2698 void *
conv_text_m2d_W2W(DM_CONV * conv,void * inStr,SQLLEN size,SQLLEN * copied)2699 conv_text_m2d_W2W(DM_CONV *conv, void *inStr, SQLLEN size, SQLLEN *copied)
2700 {
2701   IODBC_CHARSET m_charset = (conv) ? conv->dm_cp : CP_DEF;
2702   IODBC_CHARSET d_charset = (conv) ? conv->drv_cp : CP_DEF;
2703   void *outStr = NULL;
2704   int len;
2705   int rc;
2706 
2707   if (inStr == NULL)
2708     return NULL;
2709 
2710   len = size / DM_WCHARSIZE(conv);
2711 
2712   if (len < 0)
2713     return NULL;
2714 
2715   outStr = calloc(len + 1, DRV_WCHARSIZE_ALLOC(conv));
2716 
2717   if (outStr)
2718     {
2719       rc = dm_conv_W2W(inStr, len, outStr, len*DRV_WCHARSIZE_ALLOC(conv),
2720 		m_charset, d_charset);
2721       if (copied)
2722         *copied = rc;
2723     }
2724 
2725   return outStr;
2726 }
2727