2 * WideCharToMultiByte implementation
4 * Copyright 2000 Alexandre Julliard
10 #include "wine/unicode.h"
12 /* wcstombs for single-byte code page */
13 static inline int wcstombs_sbcs( const struct sbcs_table
*table
,
14 const WCHAR
*src
, unsigned int srclen
,
15 char *dst
, unsigned int dstlen
)
17 const unsigned char * const uni2cp_low
= table
->uni2cp_low
;
18 const unsigned short * const uni2cp_high
= table
->uni2cp_high
;
23 /* buffer too small: fill it up to dstlen and return error */
33 case 16: dst
[15] = uni2cp_low
[uni2cp_high
[src
[15] >> 8] + (src
[15] & 0xff)];
34 case 15: dst
[14] = uni2cp_low
[uni2cp_high
[src
[14] >> 8] + (src
[14] & 0xff)];
35 case 14: dst
[13] = uni2cp_low
[uni2cp_high
[src
[13] >> 8] + (src
[13] & 0xff)];
36 case 13: dst
[12] = uni2cp_low
[uni2cp_high
[src
[12] >> 8] + (src
[12] & 0xff)];
37 case 12: dst
[11] = uni2cp_low
[uni2cp_high
[src
[11] >> 8] + (src
[11] & 0xff)];
38 case 11: dst
[10] = uni2cp_low
[uni2cp_high
[src
[10] >> 8] + (src
[10] & 0xff)];
39 case 10: dst
[9] = uni2cp_low
[uni2cp_high
[src
[9] >> 8] + (src
[9] & 0xff)];
40 case 9: dst
[8] = uni2cp_low
[uni2cp_high
[src
[8] >> 8] + (src
[8] & 0xff)];
41 case 8: dst
[7] = uni2cp_low
[uni2cp_high
[src
[7] >> 8] + (src
[7] & 0xff)];
42 case 7: dst
[6] = uni2cp_low
[uni2cp_high
[src
[6] >> 8] + (src
[6] & 0xff)];
43 case 6: dst
[5] = uni2cp_low
[uni2cp_high
[src
[5] >> 8] + (src
[5] & 0xff)];
44 case 5: dst
[4] = uni2cp_low
[uni2cp_high
[src
[4] >> 8] + (src
[4] & 0xff)];
45 case 4: dst
[3] = uni2cp_low
[uni2cp_high
[src
[3] >> 8] + (src
[3] & 0xff)];
46 case 3: dst
[2] = uni2cp_low
[uni2cp_high
[src
[2] >> 8] + (src
[2] & 0xff)];
47 case 2: dst
[1] = uni2cp_low
[uni2cp_high
[src
[1] >> 8] + (src
[1] & 0xff)];
48 case 1: dst
[0] = uni2cp_low
[uni2cp_high
[src
[0] >> 8] + (src
[0] & 0xff)];
51 if (srclen
< 16) return ret
;
58 /* slow version of wcstombs_sbcs that handles the various flags */
59 static int wcstombs_sbcs_slow( const struct sbcs_table
*table
, int flags
,
60 const WCHAR
*src
, unsigned int srclen
,
61 char *dst
, unsigned int dstlen
,
62 const char *defchar
, int *used
)
64 const WCHAR
* const cp2uni
= table
->cp2uni
;
65 const unsigned char * const uni2cp_low
= table
->uni2cp_low
;
66 const unsigned short * const uni2cp_high
= table
->uni2cp_high
;
67 const unsigned char table_default
= table
->info
.def_char
& 0xff;
68 int ret
= srclen
, tmp
;
72 /* buffer too small: fill it up to dstlen and return error */
77 if (!defchar
) defchar
= &table_default
;
78 if (!used
) used
= &tmp
; /* avoid checking on every char */
82 unsigned char ch
= uni2cp_low
[uni2cp_high
[*src
>> 8] + (*src
& 0xff)];
83 if (((flags
& WC_NO_BEST_FIT_CHARS
) && (cp2uni
[ch
] != *src
)) ||
84 (ch
== table_default
&& *src
!= table
->info
.def_unicode_char
))
96 /* query necessary dst length for src string */
97 static inline int get_length_dbcs( const struct dbcs_table
*table
,
98 const WCHAR
*src
, unsigned int srclen
)
100 const unsigned short * const uni2cp_low
= table
->uni2cp_low
;
101 const unsigned short * const uni2cp_high
= table
->uni2cp_high
;
104 for (len
= 0; srclen
; srclen
--, src
++, len
++)
106 if (uni2cp_low
[uni2cp_high
[*src
>> 8] + (*src
& 0xff)] & 0xff00) len
++;
111 /* wcstombs for double-byte code page */
112 static inline int wcstombs_dbcs( const struct dbcs_table
*table
,
113 const WCHAR
*src
, unsigned int srclen
,
114 char *dst
, unsigned int dstlen
)
116 const unsigned short * const uni2cp_low
= table
->uni2cp_low
;
117 const unsigned short * const uni2cp_high
= table
->uni2cp_high
;
120 for (len
= dstlen
; srclen
&& len
; len
--, srclen
--, src
++)
122 unsigned short res
= uni2cp_low
[uni2cp_high
[*src
>> 8] + (*src
& 0xff)];
125 if (len
== 1) break; /* do not output a partial char */
131 if (srclen
) return -1; /* overflow */
135 /* slow version of wcstombs_dbcs that handles the various flags */
136 static int wcstombs_dbcs_slow( const struct dbcs_table
*table
, int flags
,
137 const WCHAR
*src
, unsigned int srclen
,
138 char *dst
, unsigned int dstlen
,
139 const char *defchar
, int *used
)
141 const WCHAR
* const cp2uni
= table
->cp2uni
;
142 const unsigned short * const uni2cp_low
= table
->uni2cp_low
;
143 const unsigned short * const uni2cp_high
= table
->uni2cp_high
;
144 const unsigned char * const cp2uni_lb
= table
->cp2uni_leadbytes
;
145 WCHAR defchar_value
= table
->info
.def_char
;
148 if (defchar
) defchar_value
= defchar
[1] ? ((defchar
[0] << 8) | defchar
[1]) : defchar
[0];
149 if (!used
) used
= &tmp
; /* avoid checking on every char */
151 for (len
= dstlen
; srclen
&& len
; len
--, srclen
--, src
++)
153 unsigned short res
= uni2cp_low
[uni2cp_high
[*src
>> 8] + (*src
& 0xff)];
155 if (res
== table
->info
.def_char
&& *src
!= table
->info
.def_unicode_char
)
160 else if (flags
& WC_NO_BEST_FIT_CHARS
)
162 /* check if char maps back to the same Unicode value */
165 unsigned char off
= cp2uni_lb
[res
>> 8];
166 if (cp2uni
[(off
<< 8) + (res
& 0xff)] != *src
)
172 else if (cp2uni
[res
& 0xff] != *src
)
181 if (len
== 1) break; /* do not output a partial char */
187 if (srclen
) return -1; /* overflow */
191 /* wide char to multi byte string conversion */
192 /* return -1 on dst buffer overflow */
193 int cp_wcstombs( const union cptable
*table
, int flags
,
194 const WCHAR
*src
, int srclen
,
195 char *dst
, int dstlen
, const char *defchar
, int *used
)
197 if (table
->info
.char_size
== 1)
199 if (!dstlen
) return srclen
;
200 if (flags
|| defchar
|| used
)
201 return wcstombs_sbcs_slow( &table
->sbcs
, flags
, src
, srclen
,
202 dst
, dstlen
, defchar
, used
);
203 return wcstombs_sbcs( &table
->sbcs
, src
, srclen
, dst
, dstlen
);
207 if (!dstlen
) return get_length_dbcs( &table
->dbcs
, src
, srclen
);
208 if (flags
|| defchar
|| used
)
209 return wcstombs_dbcs_slow( &table
->dbcs
, flags
, src
, srclen
,
210 dst
, dstlen
, defchar
, used
);
211 return wcstombs_dbcs( &table
->dbcs
, src
, srclen
, dst
, dstlen
);