NCBI C++ ToolKit
iconv.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
3  * Copyright (C) 2010 Frediano Ziglio
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 /**
22  * \file
23  * \brief Handle character conversions to/from server
24  */
25 
26 #include <config.h>
27 
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <assert.h>
31 
32 #if HAVE_STRING_H
33 #include <string.h>
34 #endif /* HAVE_STRING_H */
35 #if HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38 
39 #include <freetds/tds.h>
40 #include <freetds/iconv.h>
41 #if HAVE_ICONV
42 #include <iconv.h>
43 #endif
44 
45 #define CHARSIZE(charset) ( ((charset)->min_bytes_per_char == (charset)->max_bytes_per_char )? \
46  (charset)->min_bytes_per_char : 0 )
47 
48 
49 static int collate2charset(int sql_collate, int lcid);
50 static size_t skip_one_input_sequence(iconv_t cd, const TDS_ENCODING * charset, const char **input, size_t * input_size);
51 static int tds_iconv_info_init(TDSICONV * char_conv, int client_canonic, int server_canonic);
52 static int tds_iconv_init(void);
53 static int tds_canonical_charset(const char *charset_name);
54 static void _iconv_close(iconv_t * cd);
55 static void tds_iconv_info_close(TDSICONV * char_conv);
56 
57 
58 /**
59  * \ingroup libtds
60  * \defgroup conv Charset conversion
61  * Convert between different charsets.
62  */
63 
64 #define TDS_ICONV_ENCODING_TABLES
65 #include "encodings.h"
66 
67 /* this will contain real iconv names */
68 static const char *iconv_names[sizeof(canonic_charsets) / sizeof(canonic_charsets[0])];
69 static int iconv_initialized = 0;
70 static const char *ucs2name;
71 #ifdef TDS_HAVE_MUTEX
73 #endif
74 
75 enum
77 
78 /**
79  * Initialize charset searching for UTF-8, UCS-2 and ISO8859-1
80  */
81 static int
83 {
84  int i;
85  iconv_t cd;
86 
87  /* first entries should be constants */
88  assert(strcmp(canonic_charsets[POS_ISO1].name, "ISO-8859-1") == 0);
89  assert(strcmp(canonic_charsets[POS_UTF8].name, "UTF-8") == 0);
90  assert(strcmp(canonic_charsets[POS_UCS2LE].name, "UCS-2LE") == 0);
91  assert(strcmp(canonic_charsets[POS_UCS2BE].name, "UCS-2BE") == 0);
92 
93  /* fast tests for GNU-iconv */
94  cd = tds_sys_iconv_open("ISO-8859-1", "UTF-8");
95  if (cd != (iconv_t) -1) {
96  iconv_names[POS_ISO1] = "ISO-8859-1";
97  iconv_names[POS_UTF8] = "UTF-8";
99  } else {
100 
101  /* search names for ISO8859-1 and UTF-8 */
102  for (i = 0; iconv_aliases[i].alias; ++i) {
103  int j;
104 
105  if (iconv_aliases[i].canonic != POS_ISO1)
106  continue;
107  for (j = 0; iconv_aliases[j].alias; ++j) {
108  if (iconv_aliases[j].canonic != POS_UTF8)
109  continue;
110 
111  cd = tds_sys_iconv_open(iconv_aliases[i].alias, iconv_aliases[j].alias);
112  if (cd != (iconv_t) -1) {
113  iconv_names[POS_ISO1] = iconv_aliases[i].alias;
114  iconv_names[POS_UTF8] = iconv_aliases[j].alias;
116  break;
117  }
118  }
119  if (iconv_names[POS_ISO1])
120  break;
121  }
122  /* required characters not found !!! */
123  if (!iconv_names[POS_ISO1])
124  return 1;
125  }
126 
127  /* now search for UCS-2 */
128  cd = tds_sys_iconv_open(iconv_names[POS_ISO1], "UCS-2LE");
129  if (cd != (iconv_t) -1) {
130  iconv_names[POS_UCS2LE] = "UCS-2LE";
132  }
133  cd = tds_sys_iconv_open(iconv_names[POS_ISO1], "UCS-2BE");
134  if (cd != (iconv_t) -1) {
135  iconv_names[POS_UCS2BE] = "UCS-2BE";
137  }
138 
139  /* long search needed ?? */
141  for (i = 0; iconv_aliases[i].alias; ++i) {
142  if (strncmp(canonic_charsets[iconv_aliases[i].canonic].name, "UCS-2", 5) != 0)
143  continue;
144 
145  cd = tds_sys_iconv_open(iconv_aliases[i].alias, iconv_names[POS_ISO1]);
146  if (cd != (iconv_t) -1) {
147  char ib[1];
148  char ob[4];
149  size_t il, ol;
150  ICONV_CONST char *pib;
151  char *pob;
152  int byte_sequence = 0;
153 
154  /* try to convert 'A' and check result */
155  ib[0] = 0x41;
156  pib = ib;
157  pob = ob;
158  il = 1;
159  ol = 4;
160  ob[0] = ob[1] = 0;
161  if (tds_sys_iconv(cd, &pib, &il, &pob, &ol) != (size_t) - 1) {
162  /* byte order sequence ?? */
163  if (ol == 0) {
164  ob[0] = ob[2];
165  byte_sequence = 1;
166  /* TODO save somewhere */
167  }
168 
169  /* save name without sequence (if present) */
170  if (ob[0])
171  il = POS_UCS2LE;
172  else
173  il = POS_UCS2BE;
174  if (!iconv_names[il] || !byte_sequence)
175  iconv_names[il] = iconv_aliases[i].alias;
176  }
178  }
179  }
180  }
181  /* we need a UCS-2 (big endian or little endian) */
183  return 2;
184 
186 
187  for (i = 0; i < 4; ++i)
188  tdsdump_log(TDS_DBG_INFO1, "local name for %s is %s\n", canonic_charsets[i].name,
189  iconv_names[i] ? iconv_names[i] : "(null)");
190 
191  /* success (it should always occurs) */
192  return 0;
193 }
194 
195 /**
196  * Get iconv name given canonic
197  */
198 static const char *
199 tds_set_iconv_name(int charset)
200 {
201  int i;
202  iconv_t cd;
203 
204 #ifdef TDS_HAVE_MUTEX
206 #endif
208 
209  /* try using canonic name and UTF-8 and UCS2 */
210  cd = tds_sys_iconv_open(iconv_names[POS_UTF8], canonic_charsets[charset].name);
211  if (cd != (iconv_t) -1) {
212  iconv_names[charset] = canonic_charsets[charset].name;
214 #ifdef TDS_HAVE_MUTEX
216 #endif
217  return iconv_names[charset];
218  }
219  cd = tds_sys_iconv_open(ucs2name, canonic_charsets[charset].name);
220  if (cd != (iconv_t) -1) {
221  iconv_names[charset] = canonic_charsets[charset].name;
223 #ifdef TDS_HAVE_MUTEX
225 #endif
226  return iconv_names[charset];
227  }
228 
229  /* try all alternatives */
230  for (i = 0; iconv_aliases[i].alias; ++i) {
231  if (iconv_aliases[i].canonic != charset)
232  continue;
233 
234  cd = tds_sys_iconv_open(iconv_names[POS_UTF8], iconv_aliases[i].alias);
235  if (cd != (iconv_t) -1) {
236  iconv_names[charset] = iconv_aliases[i].alias;
238 #ifdef TDS_HAVE_MUTEX
240 #endif
241  return iconv_names[charset];
242  }
243 
244  cd = tds_sys_iconv_open(ucs2name, iconv_aliases[i].alias);
245  if (cd != (iconv_t) -1) {
246  iconv_names[charset] = iconv_aliases[i].alias;
248 #ifdef TDS_HAVE_MUTEX
250 #endif
251  return iconv_names[charset];
252  }
253  }
254 
255  /* charset not found, pretend it's ISO 8859-1 */
256  iconv_names[charset] = canonic_charsets[POS_ISO1].name;
257 #ifdef TDS_HAVE_MUTEX
259 #endif
260  return NULL;
261 }
262 
263 static void
265 {
266  /*
267  * (min|max)_bytes_per_char can be used to divide
268  * so init to safe values
269  */
270  conv->to.charset.min_bytes_per_char = 1;
271  conv->to.charset.max_bytes_per_char = 1;
274 
275  conv->to.charset.name = conv->from.charset.name = "";
276  conv->to.charset.canonic = conv->from.charset.canonic = 0;
277  conv->to.cd = (iconv_t) -1;
278  conv->from.cd = (iconv_t) -1;
279 }
280 
281 /**
282  * Allocate iconv stuff
283  * \return 0 for success
284  */
285 int
287 {
288  int i;
289  TDSICONV *char_conv;
290 
291  assert(!conn->char_convs);
292  if (!(conn->char_convs = tds_new(TDSICONV *, initial_char_conv_count + 1)))
293  return 1;
295  if (!char_conv) {
296  TDS_ZERO_FREE(conn->char_convs);
297  return 1;
298  }
299  conn->char_conv_count = initial_char_conv_count + 1;
300 
301  for (i = 0; i < initial_char_conv_count; ++i) {
302  conn->char_convs[i] = &char_conv[i];
303  tds_iconv_reset(&char_conv[i]);
304  }
305 
306  /* chardata is just a pointer to another iconv info */
307  conn->char_convs[initial_char_conv_count] = conn->char_convs[client2server_chardata];
308 
309  return 0;
310 }
311 
312 /**
313  * \addtogroup conv
314  * @{
315  * Set up the initial iconv conversion descriptors.
316  * When the socket is allocated, three TDSICONV structures are attached to iconv.
317  * They have fixed meanings:
318  * \li 0. Client <-> UCS-2 (client2ucs2)
319  * \li 1. Client <-> server single-byte charset (client2server_chardata)
320  *
321  * Other designs that use less data are possible, but these three conversion needs are
322  * very often needed. By reserving them, we avoid searching the array for our most common purposes.
323  *
324  * To solve different iconv names and portability problems FreeTDS maintains
325  * a list of aliases each charset.
326  *
327  * First we discover the names of our minimum required charsets (UTF-8, ISO8859-1 and UCS2).
328  * Later, as and when it's needed, we try to discover others.
329  *
330  * There is one list of canonic names (GNU iconv names) and two sets of aliases
331  * (one for other iconv implementations and another for Sybase). For every
332  * canonic charset name we cache the iconv name found during discovery.
333  */
334 TDSRET
335 tds_iconv_open(TDSCONNECTION * conn, const char *charset, int use_utf16)
336 {
337  static const char UCS_2LE[] = "UCS-2LE";
338  int canonic;
339  int canonic_charset = tds_canonical_charset(charset);
340  int canonic_env_charset = conn->env.charset ? tds_canonical_charset(conn->env.charset) : -1;
341  int fOK, ret;
342 
343  TDS_ENCODING *client = &conn->char_convs[client2ucs2]->from.charset;
344  TDS_ENCODING *server = &conn->char_convs[client2ucs2]->to.charset;
345 
346  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_open(%p, %s)\n", conn, charset);
347 
348  /* initialize */
349 #ifdef TDS_HAVE_MUTEX
351 #endif
352  if (!iconv_initialized) {
353  if ((ret = tds_iconv_init()) > 0) {
354  static const char names[][12] = { "ISO 8859-1", "UTF-8" };
355  assert(ret < 3);
356  tdsdump_log(TDS_DBG_FUNC, "error: tds_iconv_init() returned %d; "
357  "could not find a name for %s that your iconv accepts.\n"
358  "use: \"configure --disable-libiconv\"", ret, names[ret-1]);
359 #ifdef TDS_HAVE_MUTEX
361 #endif
362  return TDS_FAIL;
363  }
364  iconv_initialized = 1;
365  }
366 #ifdef TDS_HAVE_MUTEX
368 #endif
369 
370  /*
371  * Client <-> UCS-2 (client2ucs2)
372  */
373  tdsdump_log(TDS_DBG_FUNC, "setting up conversions for client charset \"%s\"\n", charset);
374 
375  tdsdump_log(TDS_DBG_FUNC, "preparing iconv for \"%s\" <-> \"%s\" conversion\n", charset, UCS_2LE);
376 
377  fOK = 0;
378  if (use_utf16) {
379  canonic = TDS_CHARSET_UTF_16LE;
380  fOK = tds_iconv_info_init(conn->char_convs[client2ucs2], canonic_charset, canonic);
381  }
382  if (!fOK) {
383  canonic = TDS_CHARSET_UCS_2LE;
384  fOK = tds_iconv_info_init(conn->char_convs[client2ucs2], canonic_charset, canonic);
385  }
386  if (!fOK)
387  return TDS_FAIL;
388 
389  /*
390  * How many UTF-8 bytes we need is a function of what the input character set is.
391  * TODO This could definitely be more sophisticated, but it deals with the common case.
392  */
393  if (client->min_bytes_per_char == 1 && client->max_bytes_per_char == 4 && server->max_bytes_per_char == 1) {
394  /* ie client is UTF-8 and server is ISO-8859-1 or variant. */
395  client->max_bytes_per_char = 3;
396  }
397 
398  /*
399  * Client <-> server single-byte charset
400  * TODO: the server hasn't reported its charset yet, so this logic can't work here.
401  * not sure what to do about that yet.
402  */
403  conn->char_convs[client2server_chardata]->flags = TDS_ENCODING_MEMCPY;
404  if (canonic_env_charset >= 0) {
405  tdsdump_log(TDS_DBG_FUNC, "preparing iconv for \"%s\" <-> \"%s\" conversion\n", charset, conn->env.charset);
406  fOK = tds_iconv_info_init(conn->char_convs[client2server_chardata], canonic_charset, canonic_env_charset);
407  if (!fOK)
408  return TDS_FAIL;
409  } else {
410  conn->char_convs[client2server_chardata]->from.charset = canonic_charsets[canonic_charset];
411  conn->char_convs[client2server_chardata]->to.charset = canonic_charsets[canonic_charset];
412  }
413 
414  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_open: done\n");
415  return TDS_SUCCESS;
416 }
417 
418 /**
419  * Open iconv descriptors to convert between character sets (both directions).
420  * 1. Look up the canonical names of the character sets.
421  * 2. Look up their widths.
422  * 3. Ask iconv to open a conversion descriptor.
423  * 4. Fail if any of the above offer any resistance.
424  * \remarks The charset names written to \a iconv will be the canonical names,
425  * not necessarily the names passed in.
426  */
427 static int
428 tds_iconv_info_init(TDSICONV * char_conv, int client_canonical, int server_canonical)
429 {
430  TDS_ENCODING *client = &char_conv->from.charset;
431  TDS_ENCODING *server = &char_conv->to.charset;
432 
433  assert(char_conv->to.cd == (iconv_t) -1);
434  assert(char_conv->from.cd == (iconv_t) -1);
435 
436  if (client_canonical < 0) {
437  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_info_init: client charset name \"%d\" invalid\n", client_canonical);
438  return 0;
439  }
440 
441  if (server_canonical < 0) {
442  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_info_init: server charset name \"%d\" invalid\n", server_canonical);
443  return 0;
444  }
445 
446  *client = canonic_charsets[client_canonical];
447  *server = canonic_charsets[server_canonical];
448 
449  /* special case, same charset, no conversion */
450  if (client_canonical == server_canonical) {
451  char_conv->to.cd = (iconv_t) -1;
452  char_conv->from.cd = (iconv_t) -1;
453  char_conv->flags = TDS_ENCODING_MEMCPY;
454  return 1;
455  }
456 
457  char_conv->flags = 0;
458 
459  /* get iconv names */
460  if (!iconv_names[client_canonical]) {
461  if (!tds_set_iconv_name(client_canonical)) {
462  tdsdump_log(TDS_DBG_FUNC, "Charset %d not supported by iconv, using \"%s\" instead\n",
463  client_canonical, iconv_names[client_canonical]);
464  }
465  }
466 
467  if (!iconv_names[server_canonical]) {
468  if (!tds_set_iconv_name(server_canonical)) {
469  tdsdump_log(TDS_DBG_FUNC, "Charset %d not supported by iconv, using \"%s\" instead\n",
470  server_canonical, iconv_names[server_canonical]);
471  }
472  }
473 
474  char_conv->to.cd = tds_sys_iconv_open(iconv_names[server_canonical], iconv_names[client_canonical]);
475  if (char_conv->to.cd == (iconv_t) -1) {
476  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_info_init: cannot convert \"%s\"->\"%s\"\n", client->name, server->name);
477  }
478 
479  char_conv->from.cd = tds_sys_iconv_open(iconv_names[client_canonical], iconv_names[server_canonical]);
480  if (char_conv->from.cd == (iconv_t) -1) {
481  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_info_init: cannot convert \"%s\"->\"%s\"\n", server->name, client->name);
482  }
483 
484  /* TODO, do some optimizations like UCS2 -> UTF8 min,max = 2,2 (UCS2) and 1,4 (UTF8) */
485 
486  /* tdsdump_log(TDS_DBG_FUNC, "tds_iconv_info_init: converting \"%s\"->\"%s\"\n", client->name, server->name); */
487 
488  return 1;
489 }
490 
491 
492 static void
494 {
495  static const iconv_t invalid = (iconv_t) -1;
496 
497  if (*cd != invalid) {
498  tds_sys_iconv_close(*cd);
499  *cd = invalid;
500  }
501 }
502 
503 static void
505 {
506  _iconv_close(&char_conv->to.cd);
507  _iconv_close(&char_conv->from.cd);
508 }
509 
510 void
512 {
513  int i;
514 
515  for (i = 0; i < conn->char_conv_count; ++i)
516  tds_iconv_info_close(conn->char_convs[i]);
517 }
518 
519 #define CHUNK_ALLOC 4
520 
521 void
523 {
524  int i;
525 
526  if (!conn->char_convs)
527  return;
529 
530  free(conn->char_convs[0]);
531  for (i = initial_char_conv_count + 1; i < conn->char_conv_count; i += CHUNK_ALLOC)
532  free(conn->char_convs[i]);
533  TDS_ZERO_FREE(conn->char_convs);
534  conn->char_conv_count = 0;
535 }
536 
537 static void
539 {
540  if (tds)
541  tdserror(tds_get_ctx(tds), tds, err, 0);
542 }
543 
544 /**
545  * Wrapper around iconv(3). Same parameters, with slightly different behavior.
546  * \param tds state information for the socket and the TDS protocol
547  * \param io Enumerated value indicating whether the data are being sent to or received from the server.
548  * \param conv information about the encodings involved, including the iconv(3) conversion descriptors.
549  * \param inbuf address of pointer to the input buffer of data to be converted.
550  * \param inbytesleft address of count of bytes in \a inbuf.
551  * \param outbuf address of pointer to the output buffer.
552  * \param outbytesleft address of count of bytes in \a outbuf.
553  * \retval number of irreversible conversions performed. -1 on error, see iconv(3) documentation for
554  * a description of the possible values of \e errno.
555  * \remarks Unlike iconv(3), none of the arguments can be nor point to NULL. Like iconv(3), all pointers will
556  * be updated. Success is signified by a nonnegative return code and \a *inbytesleft == 0.
557  * If the conversion descriptor in \a iconv is -1 or NULL, \a inbuf is copied to \a outbuf,
558  * and all parameters updated accordingly.
559  *
560  * If a character in \a inbuf cannot be converted because no such cbaracter exists in the
561  * \a outbuf character set, we emit messages similar to the ones Sybase emits when it fails such a conversion.
562  * The message varies depending on the direction of the data.
563  * On a read error, we emit Msg 2403, Severity 16 (EX_INFO):
564  * "WARNING! Some character(s) could not be converted into client's character set.
565  * Unconverted bytes were changed to question marks ('?')."
566  * On a write error we emit Msg 2402, Severity 16 (EX_USER):
567  * "Error converting client characters into server's character set. Some character(s) could not be converted."
568  * and return an error code. Client libraries relying on this routine should reflect an error back to the application.
569  *
570  * \todo Check for variable multibyte non-UTF-8 input character set.
571  * \todo Use more robust error message generation.
572  * \todo For reads, cope with \a outbuf encodings that don't have the equivalent of an ASCII '?'.
573  * \todo Support alternative to '?' for the replacement character.
574  */
575 size_t
577  const char **inbuf, size_t * inbytesleft, char **outbuf, size_t * outbytesleft)
578 {
579  static const iconv_t invalid = (iconv_t) -1;
580  TDSICONVDIR *from = NULL;
581  TDSICONVDIR *to = NULL;
582 
583  iconv_t error_cd = invalid;
584 
585  char quest_mark[] = "?"; /* best to leave non-const; implementations vary */
586  ICONV_CONST char *pquest_mark = quest_mark;
587  size_t lquest_mark;
588  size_t irreversible;
589  size_t one_character;
590  int eilseq_raised = 0;
591  int conv_errno;
592  /* cast away const-ness */
594 
595  assert(inbuf && inbytesleft && outbuf && outbytesleft);
596 
597  /* if empty there's nothing to return.
598  * This fix case with some iconv implementation that does
599  * not handle *inbuf == NULL and *inbytesleft == 0 as
600  * empty strings
601  */
602  if (*inbytesleft == 0)
603  return 0;
604 
605  switch (io) {
606  case to_server:
607  from = &conv->from;
608  to = &conv->to;
609  break;
610  case to_client:
611  from = &conv->to;
612  to = &conv->from;
613  break;
614  default:
615  tdsdump_log(TDS_DBG_FUNC, "tds_iconv: unable to determine if %d means in or out. \n", io);
616  assert(io == to_server || io == to_client);
617  break;
618  }
619 
620  /* silly case, memcpy */
621  if (conv->flags & TDS_ENCODING_MEMCPY || to->cd == invalid) {
622  size_t len = *inbytesleft < *outbytesleft ? *inbytesleft : *outbytesleft;
623 
624  memcpy(*outbuf, *inbuf, len);
625  errno = *inbytesleft > *outbytesleft ? E2BIG : 0;
626  *inbytesleft -= len;
627  *outbytesleft -= len;
628  *inbuf += len;
629  *outbuf += len;
630  return 0;
631  }
632 
633  /*
634  * Call iconv() as many times as necessary, until we reach the end of input or exhaust output.
635  */
636  for (;;) {
637  conv_errno = 0;
638  irreversible = tds_sys_iconv(to->cd, (ICONV_CONST char **) inbuf, inbytesleft, outbuf, outbytesleft);
639 
640  /* iconv success, return */
641  if (irreversible != (size_t) - 1) {
642  if (irreversible > 0) {
643  eilseq_raised = 1;
644  }
645  /* here we detect end of conversion and try to reset shift state */
646  if (inbuf) {
647  /*
648  * if inbuf or *inbuf is NULL iconv reset the shift state.
649  * Note that setting inbytesleft to NULL can cause core so don't do it!
650  */
651  inbuf = NULL;
652  continue;
653  }
654  break;
655  }
656 
657  /* save errno, other function could change its value */
658  conv_errno = errno;
659 
660  if (conv_errno == EILSEQ)
661  eilseq_raised = 1;
662 
663  if (!eilseq_raised || io != to_client || !inbuf)
664  break;
665  /*
666  * Invalid input sequence encountered reading from server.
667  * Skip one input sequence, adjusting pointers.
668  */
669  one_character = skip_one_input_sequence(to->cd, &from->charset, inbuf, inbytesleft);
670 
671  if (!one_character)
672  break;
673 
674  /*
675  * To replace invalid input with '?', we have to convert a UTF-8 '?' into the output character set.
676  * In unimaginably weird circumstances, this might be impossible.
677  * We use UTF-8 instead of ASCII because some implementations
678  * do not convert singlebyte <-> singlebyte.
679  */
680  if (error_cd == invalid) {
682  if (error_cd == invalid) {
683  break; /* what to do? */
684  }
685  }
686 
687  lquest_mark = 1;
688  pquest_mark = quest_mark;
689 
690  irreversible = tds_sys_iconv(error_cd, &pquest_mark, &lquest_mark, outbuf, outbytesleft);
691 
692  if (irreversible == (size_t) - 1)
693  break;
694 
695  if (!*inbytesleft)
696  break;
697  }
698 
699  if (eilseq_raised && !suppress->eilseq) {
700  /* invalid multibyte input sequence encountered */
701  if (io == to_client) {
702  if (irreversible == (size_t) - 1) {
704  } else {
706  conv_errno = 0;
707  }
708  } else {
710  }
711  suppress->eilseq = 1;
712  }
713 
714  switch (conv_errno) {
715  case EINVAL: /* incomplete multibyte sequence is encountered */
716  if (suppress->einval)
717  break;
718  /* in chunk conversion this can mean we end a chunk inside a character */
720  suppress->einval = 1;
721  break;
722  case E2BIG: /* output buffer has no more room */
723  if (suppress->e2big)
724  break;
726  suppress->e2big = 1;
727  break;
728  default:
729  break;
730  }
731 
732  if (error_cd != invalid) {
733  tds_sys_iconv_close(error_cd);
734  }
735 
736  errno = conv_errno;
737  return irreversible;
738 }
739 
740 /**
741  * Get a iconv info structure, allocate and initialize if needed
742  */
743 static TDSICONV *
744 tds_iconv_get_info(TDSCONNECTION * conn, int canonic_client, int canonic_server)
745 {
746  TDSICONV *info;
747  int i;
748 
749  /* search a charset from already allocated charsets */
750  for (i = conn->char_conv_count; --i >= initial_char_conv_count;)
751  if (canonic_client == conn->char_convs[i]->from.charset.canonic
752  && canonic_server == conn->char_convs[i]->to.charset.canonic)
753  return conn->char_convs[i];
754 
755  /* allocate a new iconv structure */
756  if (conn->char_conv_count % CHUNK_ALLOC == ((initial_char_conv_count + 1) % CHUNK_ALLOC)) {
757  TDSICONV **p;
758  TDSICONV *infos;
759 
760  infos = tds_new(TDSICONV, CHUNK_ALLOC);
761  if (!infos)
762  return NULL;
763  p = (TDSICONV **) realloc(conn->char_convs, sizeof(TDSICONV *) * (conn->char_conv_count + CHUNK_ALLOC));
764  if (!p) {
765  free(infos);
766  return NULL;
767  }
768  conn->char_convs = p;
769  memset(infos, 0, sizeof(TDSICONV) * CHUNK_ALLOC);
770  for (i = 0; i < CHUNK_ALLOC; ++i) {
771  conn->char_convs[i + conn->char_conv_count] = &infos[i];
772  tds_iconv_reset(&infos[i]);
773  }
774  }
775  info = conn->char_convs[conn->char_conv_count++];
776 
777  /* init */
778  if (tds_iconv_info_init(info, canonic_client, canonic_server))
779  return info;
780 
782  --conn->char_conv_count;
783  return NULL;
784 }
785 
786 TDSICONV *
787 tds_iconv_get(TDSCONNECTION * conn, const char *client_charset, const char *server_charset)
788 {
789  int canonic_client_charset_num = tds_canonical_charset(client_charset);
790  int canonic_server_charset_num = tds_canonical_charset(server_charset);
791 
792  if (canonic_client_charset_num < 0) {
793  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_get: what is charset \"%s\"?\n", client_charset);
794  return NULL;
795  }
796  if (canonic_server_charset_num < 0) {
797  tdsdump_log(TDS_DBG_FUNC, "tds_iconv_get: what is charset \"%s\"?\n", server_charset);
798  return NULL;
799  }
800 
801  return tds_iconv_get_info(conn, canonic_client_charset_num, canonic_server_charset_num);
802 }
803 
804 /* change singlebyte conversions according to server */
805 static void
806 tds_srv_charset_changed_num(TDSCONNECTION * conn, int canonic_charset_num)
807 {
808  TDSICONV *char_conv = conn->char_convs[client2server_chardata];
809 
810  if (IS_TDS7_PLUS(conn) && canonic_charset_num == TDS_CHARSET_ISO_8859_1)
811  canonic_charset_num = TDS_CHARSET_CP1252;
812 
813  tdsdump_log(TDS_DBG_FUNC, "setting server single-byte charset to \"%s\"\n", canonic_charsets[canonic_charset_num].name);
814 
815  if (canonic_charset_num == char_conv->to.charset.canonic)
816  return;
817 
818  /* find and set conversion */
819  char_conv = tds_iconv_get_info(conn, conn->char_convs[client2ucs2]->from.charset.canonic, canonic_charset_num);
820  if (char_conv)
821  conn->char_convs[client2server_chardata] = char_conv;
822 }
823 
824 void
826 {
827  int n = tds_canonical_charset(charset);
828 
829  /* ignore request to change to unknown charset */
830  if (n < 0) {
831  tdsdump_log(TDS_DBG_FUNC, "tds_srv_charset_changed: what is charset \"%s\"?\n", charset);
832  return;
833  }
834 
836 }
837 
838 /* change singlebyte conversions according to server */
839 void
840 tds7_srv_charset_changed(TDSCONNECTION * conn, int sql_collate, int lcid)
841 {
842  tds_srv_charset_changed_num(conn, collate2charset(sql_collate, lcid));
843 }
844 
845 /**
846  * Move the input sequence pointer to the next valid position.
847  * Used when an input character cannot be converted.
848  * \returns number of bytes to skip.
849  */
850 /* FIXME possible buffer reading overflow ?? */
851 static size_t
852 skip_one_input_sequence(iconv_t cd, const TDS_ENCODING * charset, const char **input, size_t * input_size)
853 {
854  unsigned charsize = CHARSIZE(charset);
855  char ib[16];
856  char ob[16];
857  ICONV_CONST char *pib;
858  char *pob;
859  size_t il, ol, l;
860  iconv_t cd2;
861 
862 
863  /* usually fixed size and UTF-8 do not have state, so do not reset it */
864  if (charsize) {
865  if (charsize > *input_size)
866  return 0;
867  *input += charsize;
868  *input_size -= charsize;
869  return charsize;
870  }
871 
872  if (0 == strcmp(charset->name, "UTF-8")) {
873  /*
874  * Deal with UTF-8.
875  * bytes | bits | representation
876  * 1 | 7 | 0vvvvvvv
877  * 2 | 11 | 110vvvvv 10vvvvvv
878  * 3 | 16 | 1110vvvv 10vvvvvv 10vvvvvv
879  * 4 | 21 | 11110vvv 10vvvvvv 10vvvvvv 10vvvvvv
880  */
881  int c = **input;
882 
883  c = c & (c >> 1);
884  do {
885  ++charsize;
886  } while ((c <<= 1) & 0x80);
887  if (charsize > *input_size)
888  return 0;
889  *input += charsize;
890  *input_size -= charsize;
891  return charsize;
892  }
893 
894  /* handle state encoding */
895 
896  /* extract state from iconv */
897  pob = ib;
898  ol = sizeof(ib);
899  tds_sys_iconv(cd, NULL, NULL, &pob, &ol);
900 
901  /* init destination conversion */
902  /* TODO use largest fixed size for this platform */
903  cd2 = tds_sys_iconv_open("UCS-4", charset->name);
904  if (cd2 == (iconv_t) -1)
905  return 0;
906 
907  /* add part of input */
908  il = ol;
909  if (il > *input_size)
910  il = *input_size;
911  l = sizeof(ib) - ol;
912  memcpy(ib + l, *input, il);
913  il += l;
914 
915  /* translate a single character */
916  pib = ib;
917  pob = ob;
918  /* TODO use size of largest fixed charset */
919  ol = 4;
920  tds_sys_iconv(cd2, &pib, &il, &pob, &ol);
921 
922  /* adjust input */
923  l = (pib - ib) - l;
924  *input += l;
925  *input_size -= l;
926 
927  /* extract state */
928  pob = ib;
929  ol = sizeof(ib);
930  tds_sys_iconv(cd, NULL, NULL, &pob, &ol);
931 
932  /* set input state */
933  pib = ib;
934  il = sizeof(ib) - ol;
935  pob = ob;
936  ol = sizeof(ob);
937  tds_sys_iconv(cd, &pib, &il, &pob, &ol);
938 
939  tds_sys_iconv_close(cd2);
940 
941  return l;
942 }
943 
944 static int
945 lookup_canonic(const CHARACTER_SET_ALIAS aliases[], const char *charset_name)
946 {
947  int i;
948 
949  for (i = 0; aliases[i].alias; ++i) {
950  if (0 == strcmp(charset_name, aliases[i].alias))
951  return aliases[i].canonic;
952  }
953 
954  return -1;
955 }
956 
957 /**
958  * Determine canonical iconv character set.
959  * \returns canonical position, or -1 if lookup failed.
960  * \remarks Returned name can be used in bytes_per_char(), above.
961  */
962 static int
963 tds_canonical_charset(const char *charset_name)
964 {
965  int res;
966 
967  /* search in alternative */
968  res = lookup_canonic(iconv_aliases, charset_name);
969  if (res >= 0)
970  return res;
971 
972  /* search in sybase */
973  return lookup_canonic(sybase_aliases, charset_name);
974 }
975 
976 /**
977  * Determine canonical iconv character set name.
978  * \returns canonical name, or NULL if lookup failed.
979  * \remarks Returned name can be used in bytes_per_char(), above.
980  */
981 const char *
982 tds_canonical_charset_name(const char *charset_name)
983 {
984  int res;
985 
986  /* get numeric pos */
987  res = tds_canonical_charset(charset_name);
988  if (res >= 0)
989  return canonic_charsets[res].name;
990 
991  return charset_name; /* hope for the best */
992 }
993 
994 static int
995 collate2charset(int sql_collate, int lcid)
996 {
997  /*
998  * The table from the MSQLServer reference "Windows Collation Designators"
999  * and from " NLS Information for Microsoft Windows XP"
1000  */
1001 
1002  int cp = 0;
1003 
1004  switch (sql_collate) {
1005  case 30: /* SQL_Latin1_General_CP437_BIN */
1006  case 31: /* SQL_Latin1_General_CP437_CS_AS */
1007  case 32: /* SQL_Latin1_General_CP437_CI_AS */
1008  case 33: /* SQL_Latin1_General_Pref_CP437_CI_AS */
1009  case 34: /* SQL_Latin1_General_CP437_CI_AI */
1010  return TDS_CHARSET_CP437;
1011  case 40: /* SQL_Latin1_General_CP850_BIN */
1012  case 41: /* SQL_Latin1_General_CP850_CS_AS */
1013  case 42: /* SQL_Latin1_General_CP850_CI_AS */
1014  case 43: /* SQL_Latin1_General_Pref_CP850_CI_AS */
1015  case 44: /* SQL_Latin1_General_CP850_CI_AI */
1016  case 49: /* SQL_1xCompat_CP850_CI_AS */
1017  case 55: /* SQL_AltDiction_CP850_CS_AS */
1018  case 56: /* SQL_AltDiction_Pref_CP850_CI_AS */
1019  case 57: /* SQL_AltDiction_CP850_CI_AI */
1020  case 58: /* SQL_Scandinavian_Pref_CP850_CI_AS */
1021  case 59: /* SQL_Scandinavian_CP850_CS_AS */
1022  case 60: /* SQL_Scandinavian_CP850_CI_AS */
1023  case 61: /* SQL_AltDiction_CP850_CI_AS */
1024  return TDS_CHARSET_CP850;
1025  case 80: /* SQL_Latin1_General_1250_BIN */
1026  case 81: /* SQL_Latin1_General_CP1250_CS_AS */
1027  case 82: /* SQL_Latin1_General_CP1250_CI_AS */
1028  return TDS_CHARSET_CP1250;
1029  case 105: /* SQL_Latin1_General_CP1251_CS_AS */
1030  case 106: /* SQL_Latin1_General_CP1251_CI_AS */
1031  return TDS_CHARSET_CP1251;
1032  case 113: /* SQL_Latin1_General_CP1253_CS_AS */
1033  case 114: /* SQL_Latin1_General_CP1253_CI_AS */
1034  case 120: /* SQL_MixDiction_CP1253_CS_AS */
1035  case 121: /* SQL_AltDiction_CP1253_CS_AS */
1036  case 122: /* SQL_AltDiction2_CP1253_CS_AS */
1037  case 124: /* SQL_Latin1_General_CP1253_CI_AI */
1038  return TDS_CHARSET_CP1253;
1039  case 137: /* SQL_Latin1_General_CP1255_CS_AS */
1040  case 138: /* SQL_Latin1_General_CP1255_CI_AS */
1041  return TDS_CHARSET_CP1255;
1042  case 145: /* SQL_Latin1_General_CP1256_CS_AS */
1043  case 146: /* SQL_Latin1_General_CP1256_CI_AS */
1044  return TDS_CHARSET_CP1256;
1045  case 153: /* SQL_Latin1_General_CP1257_CS_AS */
1046  case 154: /* SQL_Latin1_General_CP1257_CI_AS */
1047  return TDS_CHARSET_CP1257;
1048  }
1049 
1050  switch (lcid & 0xffff) {
1051  case 0x405:
1052  case 0x40e: /* 0x1040e */
1053  case 0x415:
1054  case 0x418:
1055  case 0x41a:
1056  case 0x41b:
1057  case 0x41c:
1058  case 0x424:
1059  case 0x442:
1060  /* case 0x81a: seem wrong in XP table TODO check */
1061  case 0x104e: /* ?? */
1062  case 0x141a:
1063  cp = TDS_CHARSET_CP1250;
1064  break;
1065  case 0x402:
1066  case 0x419:
1067  case 0x422:
1068  case 0x423:
1069  case 0x42f:
1070  case 0x43f:
1071  case 0x440:
1072  case 0x444:
1073  case 0x450:
1074  case 0x81a: /* ?? */
1075  case 0x82c:
1076  case 0x843:
1077  case 0xc1a:
1078  cp = TDS_CHARSET_CP1251;
1079  break;
1080  case 0x1007:
1081  case 0x1009:
1082  case 0x100a:
1083  case 0x100c:
1084  case 0x1407:
1085  case 0x1409:
1086  case 0x140a:
1087  case 0x140c:
1088  case 0x1809:
1089  case 0x180a:
1090  case 0x180c:
1091  case 0x1c09:
1092  case 0x1c0a:
1093  case 0x201a:
1094  case 0x2009:
1095  case 0x200a:
1096  case 0x2409:
1097  case 0x240a:
1098  case 0x2809:
1099  case 0x280a:
1100  case 0x2c09:
1101  case 0x2c0a:
1102  case 0x3009:
1103  case 0x300a:
1104  case 0x3409:
1105  case 0x340a:
1106  case 0x380a:
1107  case 0x3c0a:
1108  case 0x400a:
1109  case 0x403:
1110  case 0x406:
1111  case 0x417:
1112  case 0x42e:
1113  case 0x43b:
1114  case 0x452:
1115  case 0x462:
1116  case 0x47a:
1117  case 0x47c:
1118  case 0x47e:
1119  case 0x483:
1120  case 0x407: /* 0x10407 */
1121  case 0x409:
1122  case 0x40a:
1123  case 0x40b:
1124  case 0x40c:
1125  case 0x40f:
1126  case 0x410:
1127  case 0x413:
1128  case 0x414:
1129  case 0x416:
1130  case 0x41d:
1131  case 0x421:
1132  case 0x42d:
1133  case 0x436:
1134  case 0x437: /* 0x10437 */
1135  case 0x438:
1136  /*case 0x439: ??? Unicode only */
1137  case 0x43e:
1138  case 0x440a:
1139  case 0x441:
1140  case 0x456:
1141  case 0x46d:
1142  case 0x485:
1143  case 0x480a:
1144  case 0x4c0a:
1145  case 0x500a:
1146  case 0x807:
1147  case 0x809:
1148  case 0x80a:
1149  case 0x80c:
1150  case 0x810:
1151  case 0x813:
1152  case 0x814:
1153  case 0x816:
1154  case 0x81d:
1155  case 0x83b:
1156  case 0x83e:
1157  case 0x85f:
1158  case 0xc07:
1159  case 0xc09:
1160  case 0xc0a:
1161  case 0xc0c:
1162  cp = TDS_CHARSET_CP1252;
1163  break;
1164  case 0x408:
1165  cp = TDS_CHARSET_CP1253;
1166  break;
1167  case 0x41f:
1168  case 0x42c:
1169  case 0x443:
1170  cp = TDS_CHARSET_CP1254;
1171  break;
1172  case 0x40d:
1173  cp = TDS_CHARSET_CP1255;
1174  break;
1175  case 0x1001:
1176  case 0x1401:
1177  case 0x1801:
1178  case 0x1c01:
1179  case 0x2001:
1180  case 0x2401:
1181  case 0x2801:
1182  case 0x2c01:
1183  case 0x3001:
1184  case 0x3401:
1185  case 0x3801:
1186  case 0x3c01:
1187  case 0x4001:
1188  case 0x401:
1189  case 0x480:
1190  case 0x420:
1191  case 0x429:
1192  case 0x48c:
1193  case 0x801:
1194  case 0xc01:
1195  cp = TDS_CHARSET_CP1256;
1196  break;
1197  case 0x425:
1198  case 0x426:
1199  case 0x427:
1200  case 0x827: /* ?? */
1201  cp = TDS_CHARSET_CP1257;
1202  break;
1203  case 0x42a:
1204  cp = TDS_CHARSET_CP1258;
1205  break;
1206  case 0x41e:
1207  cp = TDS_CHARSET_CP874;
1208  break;
1209  case 0x411: /* 0x10411 */
1210  cp = TDS_CHARSET_CP932;
1211  break;
1212  case 0x1004:
1213  case 0x804: /* 0x20804 */
1214  cp = TDS_CHARSET_CP936;
1215  break;
1216  case 0x412: /* 0x10412 */
1217  cp = TDS_CHARSET_CP949;
1218  break;
1219  case 0x1404:
1220  case 0x404: /* 0x30404 */
1221  case 0xc04:
1222  cp = TDS_CHARSET_CP950;
1223  break;
1224  default:
1225  cp = TDS_CHARSET_CP1252;
1226  }
1227 
1228  return cp;
1229 }
1230 
1231 /**
1232  * Get iconv information from a LCID (to support different column encoding under MSSQL2K)
1233  */
1234 TDSICONV *
1236 {
1237  const int sql_collate = collate[4];
1238  const int lcid = collate[1] * 256 + collate[0];
1239  int canonic_charset = collate2charset(sql_collate, lcid);
1240 
1241  /* same as client (usually this is true, so this improve performance) ? */
1242  if (conn->char_convs[client2server_chardata]->to.charset.canonic == canonic_charset)
1243  return conn->char_convs[client2server_chardata];
1244 
1245  return tds_iconv_get_info(conn, conn->char_convs[client2ucs2]->from.charset.canonic, canonic_charset);
1246 }
1247 
1248 /** @} */
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
static const struct name_t names[]
TDS_ICONV_DIRECTION
Definition: iconv.h:70
@ to_client
Definition: iconv.h:70
@ to_server
Definition: iconv.h:70
void * iconv_t
Definition: iconv.h:28
#define TDS_ENCODING_MEMCPY
Definition: iconv.h:95
#define EILSEQ
Definition: iconv.h:44
#define TDS_FAIL
Definition: tds.h:204
#define tds_new(type, n)
Definition: tds.h:1392
@ client2server_chardata
Definition: tds.h:1110
@ client2ucs2
Definition: tds.h:1109
@ initial_char_conv_count
Definition: tds.h:1111
#define tdsdump_log
Definition: tds.h:1561
#define TDS_DBG_INFO1
Definition: tds.h:900
unsigned char TDS_UCHAR
Definition: tds.h:145
@ TDSEICONVO
Definition: tds.h:299
@ TDSEICONVI
Definition: tds.h:300
@ TDSEICONV2BIG
Definition: tds.h:301
@ TDSEICONVAVAIL
Definition: tds.h:298
@ TDSEICONVIU
Definition: tds.h:297
#define IS_TDS7_PLUS(x)
Definition: tds.h:1708
#define tds_new0(type, n)
Definition: tds.h:1393
int TDSRET
Definition: tds.h:201
#define TDS_SUCCESS
Definition: tds.h:203
#define TDS_ZERO_FREE(x)
Definition: tds.h:359
#define tds_get_ctx(tds)
Definition: tds.h:1294
#define TDS_DBG_FUNC
Definition: tds.h:898
#define tds_mutex_lock(x)
Definition: thread.h:421
#define tds_mutex_unlock(x)
Definition: thread.h:423
static const char * tds_set_iconv_name(int charset)
Get iconv name given canonic.
Definition: iconv.c:199
int tds_iconv_alloc(TDSCONNECTION *conn)
Allocate iconv stuff.
Definition: iconv.c:286
static void tds_iconv_reset(TDSICONV *conv)
Definition: iconv.c:264
static const char * iconv_names[sizeof(canonic_charsets)/sizeof(canonic_charsets[0])]
Definition: iconv.c:68
static const char * ucs2name
Definition: iconv.c:70
@ POS_ISO1
Definition: iconv.c:76
@ POS_UTF8
Definition: iconv.c:76
@ POS_UCS2LE
Definition: iconv.c:76
@ POS_UCS2BE
Definition: iconv.c:76
static int tds_iconv_init(void)
Initialize charset searching for UTF-8, UCS-2 and ISO8859-1.
Definition: iconv.c:82
static int iconv_initialized
Definition: iconv.c:69
#define CHARSIZE(charset)
Definition: iconv.c:45
static TDSICONV * conv
Definition: charconv.c:168
static TDSSOCKET * tds
Definition: collations.c:37
#define tdserror
#define TDS_MUTEX_INITIALIZER
Definition: thread.h:335
#define tds_mutex
Definition: thread.h:336
uint32_t len
Definition: iconv.c:78
static tds_mutex iconv_mtx
Definition: iconv.c:72
#define NULL
Definition: ncbistd.hpp:225
static int collate2charset(int sql_collate, int lcid)
Definition: iconv.c:995
TDSRET tds_iconv_open(TDSCONNECTION *conn, const char *charset, int use_utf16)
Definition: iconv.c:335
static size_t skip_one_input_sequence(iconv_t cd, const TDS_ENCODING *charset, const char **input, size_t *input_size)
Move the input sequence pointer to the next valid position.
Definition: iconv.c:852
static int tds_canonical_charset(const char *charset_name)
Determine canonical iconv character set.
Definition: iconv.c:963
static int tds_iconv_info_init(TDSICONV *char_conv, int client_canonic, int server_canonic)
Open iconv descriptors to convert between character sets (both directions).
Definition: iconv.c:428
void tds_iconv_close(TDSCONNECTION *conn)
Definition: iconv.c:511
void tds_srv_charset_changed(TDSCONNECTION *conn, const char *charset)
Definition: iconv.c:825
const char * tds_canonical_charset_name(const char *charset_name)
Determine canonical iconv character set name.
Definition: iconv.c:982
size_t tds_sys_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
Definition: iconv.c:396
#define CHUNK_ALLOC
Definition: iconv.c:519
size_t tds_iconv(TDSSOCKET *tds, TDSICONV *conv, TDS_ICONV_DIRECTION io, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
Wrapper around iconv(3).
Definition: iconv.c:576
iconv_t tds_sys_iconv_open(const char *tocode, const char *fromcode)
Inputs are FreeTDS canonical names, no other.
Definition: iconv.c:337
TDSICONV * tds_iconv_get(TDSCONNECTION *conn, const char *client_charset, const char *server_charset)
Definition: iconv.c:787
static void tds_srv_charset_changed_num(TDSCONNECTION *conn, int canonic_charset_num)
Definition: iconv.c:806
static void _iconv_close(iconv_t *cd)
Definition: iconv.c:493
static TDSICONV * tds_iconv_get_info(TDSCONNECTION *conn, int canonic_client, int canonic_server)
Get a iconv info structure, allocate and initialize if needed.
Definition: iconv.c:744
static void tds_iconv_info_close(TDSICONV *char_conv)
Definition: iconv.c:504
static int lookup_canonic(const CHARACTER_SET_ALIAS aliases[], const char *charset_name)
Definition: iconv.c:945
void tds7_srv_charset_changed(TDSCONNECTION *conn, int sql_collate, int lcid)
Definition: iconv.c:840
void tds_iconv_free(TDSCONNECTION *conn)
Definition: iconv.c:522
static void tds_iconv_err(TDSSOCKET *tds, int err)
Definition: iconv.c:538
int tds_sys_iconv_close(iconv_t cd)
Definition: iconv.c:390
TDSICONV * tds_iconv_from_collate(TDSCONNECTION *conn, TDS_UCHAR collate[5])
Get iconv information from a LCID (to support different column encoding under MSSQL2K)
Definition: iconv.c:1235
@ TDS_CHARSET_CP936
Definition: encodings.h:503
@ TDS_CHARSET_CP850
Definition: encodings.h:498
@ TDS_CHARSET_CP950
Definition: encodings.h:505
@ TDS_CHARSET_CP1252
Definition: encodings.h:489
@ TDS_CHARSET_CP932
Definition: encodings.h:502
@ TDS_CHARSET_CP1250
Definition: encodings.h:487
@ TDS_CHARSET_CP949
Definition: encodings.h:504
@ TDS_CHARSET_CP1256
Definition: encodings.h:493
@ TDS_CHARSET_CP1251
Definition: encodings.h:488
@ TDS_CHARSET_CP874
Definition: encodings.h:501
@ TDS_CHARSET_CP1255
Definition: encodings.h:492
@ TDS_CHARSET_CP437
Definition: encodings.h:497
@ TDS_CHARSET_UCS_2LE
Definition: encodings.h:470
@ TDS_CHARSET_CP1254
Definition: encodings.h:491
@ TDS_CHARSET_UTF_16LE
Definition: encodings.h:472
@ TDS_CHARSET_CP1253
Definition: encodings.h:490
@ TDS_CHARSET_CP1258
Definition: encodings.h:495
@ TDS_CHARSET_ISO_8859_1
Definition: encodings.h:468
@ TDS_CHARSET_CP1257
Definition: encodings.h:494
static int input()
int i
yy_size_t n
static MDB_envinfo info
Definition: mdb_load.c:37
int strncmp(const char *str1, const char *str2, size_t count)
Definition: odbc_utils.hpp:133
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
#define ICONV_CONST
static SLJIT_INLINE sljit_ins l(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
static CNamedPipeClient * client
#define assert(x)
Definition: srv_diag.hpp:58
const char * alias
Definition: iconv.h:74
Information relevant to libiconv.
Definition: tds.h:683
unsigned char max_bytes_per_char
Definition: tds.h:687
const char * name
name of the encoding (ie UTF-8)
Definition: tds.h:685
unsigned char min_bytes_per_char
Definition: tds.h:686
unsigned char canonic
internal numeric index into array of all encodings
Definition: tds.h:689
unsigned int einval
Definition: iconv.h:81
unsigned int eilseq
Definition: iconv.h:80
unsigned int e2big
Definition: iconv.h:79
Information for a server connection.
Definition: tds.h:1211
TDS_ENCODING charset
Definition: iconv.h:86
iconv_t cd
Definition: iconv.h:88
unsigned int flags
Definition: iconv.h:96
struct tdsiconvdir to from
Definition: iconv.h:93
TDS_ERRNO_MESSAGE_FLAGS suppress
Definition: iconv.h:106
uchar inbuf[1000000]
Definition: unzcrash.c:40
uchar outbuf[(1000000+1000000)]
Definition: unzcrash.c:41
void free(voidpf ptr)
Modified on Fri Sep 20 14:57:31 2024 by modify_doxy.py rev. 669887