FreeBASIC  0.91.0
utf_convfrom_wchar.c
Go to the documentation of this file.
1 /* wstring to UTF conversion
2  * (based on ConvertUTF.c free implementation from Unicode, Inc)
3  */
4 
5 #include "fb.h"
6 
7 static void hUTF16ToUTF8( const FB_WCHAR *src, ssize_t chars, UTF_8 *dst, ssize_t *total_bytes )
8 {
9  UTF_32 c;
10  ssize_t bytes;
11 
12  *total_bytes = 0;
13  while( chars > 0 )
14  {
15  c = *src++;
16  if( c >= UTF16_SUR_HIGH_START && c <= UTF16_SUR_HIGH_END )
17  {
18  c = ((c - UTF16_SUR_HIGH_START) << UTF16_HALFSHIFT) +
20 
21  --chars;
22  }
23 
24  if( c < (UTF_32)0x80 )
25  bytes = 1;
26  else if( c < (UTF_32)0x800 )
27  bytes = 2;
28  else if( c < (UTF_32)0x10000 )
29  bytes = 3;
30  else
31  bytes = 4;
32 
33  dst += bytes;
34 
35  switch( bytes )
36  {
37  case 4:
38  *--dst = ((c | UTF8_BYTEMARK) & UTF8_BYTEMASK);
39  c >>= 6;
40  case 3:
41  *--dst = ((c | UTF8_BYTEMARK) & UTF8_BYTEMASK);
42  c >>= 6;
43  case 2:
44  *--dst = ((c | UTF8_BYTEMARK) & UTF8_BYTEMASK);
45  c >>= 6;
46  case 1:
47  *--dst = (c | __fb_utf8_bmarkTb[bytes]);
48  }
49 
50  dst += bytes;
51  --chars;
52  *total_bytes += bytes;
53  }
54 }
55 
56 static void hUTF32ToUTF8( const FB_WCHAR *src, ssize_t chars, UTF_8 *dst, ssize_t *total_bytes )
57 {
58  UTF_32 c;
59  ssize_t bytes;
60 
61  *total_bytes = 0;
62  while( chars > 0 )
63  {
64  c = *src++;
65  if( c < (UTF_32)0x80 )
66  bytes = 1;
67  else if( c < (UTF_32)0x800 )
68  bytes = 2;
69  else if( c < (UTF_32)0x10000 )
70  bytes = 3;
71  else
72  bytes = 4;
73 
74  dst += bytes;
75 
76  switch( bytes )
77  {
78  case 4:
79  *--dst = ((c | UTF8_BYTEMARK) & UTF8_BYTEMASK);
80  c >>= 6;
81  case 3:
82  *--dst = ((c | UTF8_BYTEMARK) & UTF8_BYTEMASK);
83  c >>= 6;
84  case 2:
85  *--dst = ((c | UTF8_BYTEMARK) & UTF8_BYTEMASK);
86  c >>= 6;
87  case 1:
88  *--dst = (c | __fb_utf8_bmarkTb[bytes]);
89  }
90 
91  dst += bytes;
92  --chars;
93  *total_bytes += bytes;
94  }
95 }
96 
97 static char *hToUTF8( const FB_WCHAR *src, ssize_t chars, char *dst, ssize_t *bytes )
98 {
99  if( chars > 0 )
100  {
101  if( dst == NULL )
102  {
103  dst = malloc( chars * 4 );
104  if( dst == NULL )
105  return NULL;
106  }
107  }
108 
109  switch( sizeof( FB_WCHAR ) )
110  {
111  case sizeof( UTF_8 ):
112  fb_hCharToUTF8( (const char *)src, chars, dst, bytes );
113  break;
114 
115  case sizeof( UTF_16 ):
116  hUTF16ToUTF8( src, chars, (UTF_8 *)dst, bytes );
117  break;
118 
119  case sizeof( UTF_32 ):
120  hUTF32ToUTF8( src, chars, (UTF_8 *)dst, bytes );
121  break;
122  }
123 
124  return dst;
125 }
126 
127 static void hCharToUTF16( const FB_WCHAR *src, ssize_t chars, UTF_16 *dst, ssize_t *bytes )
128 {
129  while( chars > 0 )
130  {
131  *dst++ = (unsigned char)*src++;
132  --chars;
133  }
134 }
135 
136 static UTF_16 *hUTF32ToUTF16( const FB_WCHAR *src, ssize_t chars, UTF_16 *dst, ssize_t *bytes )
137 {
138  UTF_16 *buffer = dst;
139  ssize_t i, dst_size = *bytes;
140  UTF_32 c;
141 
142  i = 0;
143  while( chars > 0 )
144  {
145  c = *src++;
146  if( c > UTF16_MAX_BMP )
147  {
148  if( *bytes == dst_size )
149  {
150  dst_size += sizeof( UTF_16 ) * 8;
151  buffer = realloc( buffer, dst_size );
152  dst = (UTF_16 *)buffer;
153  }
154 
155  *bytes += sizeof( UTF_16 );
156 
157  dst[i++] = (UTF_16)((c >> UTF16_HALFSHIFT) + UTF16_SUR_HIGH_START);
158  c = ((c & UTF16_HALFMASK) + UTF16_SUR_LOW_START);
159  }
160 
161  dst[i++] = (UTF_16)c;
162 
163  --chars;
164  }
165 
166  return buffer;
167 }
168 
169 static char *hToUTF16( const FB_WCHAR *src, ssize_t chars, char *dst, ssize_t *bytes )
170 {
171  /* !!!FIXME!!! only litle-endian supported */
172 
173  *bytes = chars * sizeof( UTF_16 );
174 
175  /* same size? */
176  if( sizeof( FB_WCHAR ) == sizeof( UTF_16 ) )
177  {
178  if( dst == NULL )
179  return (char *)src;
180  else
181  {
182  memcpy( dst, src, chars * sizeof( UTF_16 ) );
183  return dst;
184  }
185  }
186 
187  if( chars > 0 )
188  {
189  if( dst == NULL )
190  {
191  dst = malloc( chars * sizeof( UTF_16 ) );
192  if( dst == NULL )
193  return NULL;
194  }
195  }
196 
197  switch( sizeof( FB_WCHAR ) )
198  {
199  case sizeof( char ):
200  hCharToUTF16( src, chars, (UTF_16 *)dst, bytes );
201  break;
202 
203  case sizeof( UTF_32 ):
204  dst = (char *)hUTF32ToUTF16( src, chars, (UTF_16 *)dst, bytes );
205  break;
206  }
207 
208  return dst;
209 }
210 
211 static void hCharToUTF32( const FB_WCHAR *src, ssize_t chars, UTF_32 *dst, ssize_t *bytes )
212 {
213  while( chars > 0 )
214  {
215  *dst++ = (unsigned char)*src++;
216  --chars;
217  }
218 }
219 
220 static void hUTF16ToUTF32( const FB_WCHAR *src, ssize_t chars, UTF_32 *dst, ssize_t *bytes )
221 {
222  UTF_32 c;
223 
224  while( chars > 0 )
225  {
226  c = (UTF_32)*src++;
227  if( c >= UTF16_SUR_HIGH_START && c <= UTF16_SUR_HIGH_END )
228  {
229  c = ((c - UTF16_SUR_HIGH_START) << UTF16_HALFSHIFT) +
230  (((UTF_32)*src++) - UTF16_SUR_LOW_START) + UTF16_HALFBASE;
231 
232  *bytes -= sizeof( UTF_32 );
233  --chars;
234  }
235 
236  *dst++ = c;
237 
238  --chars;
239  }
240 }
241 
242 static char *hToUTF32( const FB_WCHAR *src, ssize_t chars, char *dst, ssize_t *bytes )
243 {
244  /* !!!FIXME!!! only litle-endian supported */
245 
246  *bytes = chars * sizeof( UTF_32 );
247 
248  /* same size? */
249  if( sizeof( FB_WCHAR ) == sizeof( UTF_32 ) )
250  {
251  if( dst == NULL )
252  return (char *)src;
253  else
254  {
255  memcpy( dst, src, chars * sizeof( UTF_32 ) );
256  return dst;
257  }
258  }
259 
260  if( chars > 0 )
261  {
262  if( dst == NULL )
263  {
264  dst = malloc( chars * sizeof( UTF_32 ) );
265  if( dst == NULL )
266  return NULL;
267  }
268  }
269 
270  switch( sizeof( FB_WCHAR ) )
271  {
272  case sizeof( char ):
273  hCharToUTF32( src, chars, (UTF_32 *)dst, bytes );
274  break;
275 
276  case sizeof( UTF_16 ):
277  hUTF16ToUTF32( src, chars, (UTF_32 *)dst, bytes );
278  break;
279  }
280 
281  return dst;
282 }
283 
284 char *fb_WCharToUTF
285  (
286  FB_FILE_ENCOD encod,
287  const FB_WCHAR *src,
288  ssize_t chars,
289  char *dst,
290  ssize_t *bytes
291  )
292 {
293  switch( encod )
294  {
295  case FB_FILE_ENCOD_UTF8:
296  return hToUTF8( src, chars, dst, bytes );
297 
298  case FB_FILE_ENCOD_UTF16:
299  return hToUTF16( src, chars, dst, bytes );
300 
301  case FB_FILE_ENCOD_UTF32:
302  return hToUTF32( src, chars, dst, bytes );
303 
304  default:
305  return NULL;
306  }
307 }