root/source3/lib/charcnv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lp_failed_convert_char
  2. charset_name
  3. lazy_initialize_conv
  4. gfree_charcnv
  5. init_iconv
  6. convert_string_internal
  7. convert_string
  8. convert_string_allocate
  9. convert_string_talloc
  10. unix_strupper
  11. strdup_upper
  12. talloc_strdup_upper
  13. unix_strlower
  14. strdup_lower
  15. talloc_strdup_lower
  16. ucs2_align
  17. push_ascii
  18. push_ascii_fstring
  19. push_ascii_nstring
  20. push_ascii_allocate
  21. pull_ascii
  22. pull_ascii_base_talloc
  23. pull_ascii_fstring
  24. pull_ascii_nstring
  25. push_ucs2
  26. push_ucs2_talloc
  27. push_ucs2_allocate
  28. push_utf8
  29. push_utf8_fstring
  30. push_utf8_talloc
  31. push_utf8_allocate
  32. pull_ucs2
  33. pull_ucs2_base_talloc
  34. pull_ucs2_fstring
  35. pull_ucs2_talloc
  36. pull_ucs2_allocate
  37. pull_utf8_talloc
  38. pull_utf8_allocate
  39. pull_ascii_talloc
  40. push_string_fn
  41. pull_string_fn
  42. pull_string_talloc_fn
  43. align_string
  44. next_codepoint

   1 /*
   2    Unix SMB/CIFS implementation.
   3    Character set conversion Extensions
   4    Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
   5    Copyright (C) Andrew Tridgell 2001
   6    Copyright (C) Simo Sorce 2001
   7    Copyright (C) Martin Pool 2003
   8 
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13 
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18 
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 
  22 */
  23 #include "includes.h"
  24 
  25 /* We can parameterize this if someone complains.... JRA. */
  26 
  27 char lp_failed_convert_char(void)
     /* [<][>][^][v][top][bottom][index][help] */
  28 {
  29         return '_';
  30 }
  31 
  32 /**
  33  * @file
  34  *
  35  * @brief Character-set conversion routines built on our iconv.
  36  *
  37  * @note Samba's internal character set (at least in the 3.0 series)
  38  * is always the same as the one for the Unix filesystem.  It is
  39  * <b>not</b> necessarily UTF-8 and may be different on machines that
  40  * need i18n filenames to be compatible with Unix software.  It does
  41  * have to be a superset of ASCII.  All multibyte sequences must start
  42  * with a byte with the high bit set.
  43  *
  44  * @sa lib/iconv.c
  45  */
  46 
  47 
  48 static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
  49 static bool conv_silent; /* Should we do a debug if the conversion fails ? */
  50 static bool initialized;
  51 
  52 /**
  53  * Return the name of a charset to give to iconv().
  54  **/
  55 static const char *charset_name(charset_t ch)
     /* [<][>][^][v][top][bottom][index][help] */
  56 {
  57         const char *ret = NULL;
  58 
  59         if (ch == CH_UTF16LE) ret = "UTF-16LE";
  60         else if (ch == CH_UTF16BE) ret = "UTF-16BE";
  61         else if (ch == CH_UNIX) ret = lp_unix_charset();
  62         else if (ch == CH_DOS) ret = lp_dos_charset();
  63         else if (ch == CH_DISPLAY) ret = lp_display_charset();
  64         else if (ch == CH_UTF8) ret = "UTF8";
  65 
  66 #if defined(HAVE_NL_LANGINFO) && defined(CODESET)
  67         if (ret && !strcmp(ret, "LOCALE")) {
  68                 const char *ln = NULL;
  69 
  70 #ifdef HAVE_SETLOCALE
  71                 setlocale(LC_ALL, "");
  72 #endif
  73                 ln = nl_langinfo(CODESET);
  74                 if (ln) {
  75                         /* Check whether the charset name is supported
  76                            by iconv */
  77                         smb_iconv_t handle = smb_iconv_open(ln,"UCS-2LE");
  78                         if (handle == (smb_iconv_t) -1) {
  79                                 DEBUG(5,("Locale charset '%s' unsupported, using ASCII instead\n", ln));
  80                                 ln = NULL;
  81                         } else {
  82                                 DEBUG(5,("Substituting charset '%s' for LOCALE\n", ln));
  83                                 smb_iconv_close(handle);
  84                         }
  85                 }
  86                 ret = ln;
  87         }
  88 #endif
  89 
  90         if (!ret || !*ret) ret = "ASCII";
  91         return ret;
  92 }
  93 
  94 void lazy_initialize_conv(void)
     /* [<][>][^][v][top][bottom][index][help] */
  95 {
  96         if (!initialized) {
  97                 load_case_tables();
  98                 init_iconv();
  99                 initialized = true;
 100         }
 101 }
 102 
 103 /**
 104  * Destroy global objects allocated by init_iconv()
 105  **/
 106 void gfree_charcnv(void)
     /* [<][>][^][v][top][bottom][index][help] */
 107 {
 108         int c1, c2;
 109 
 110         for (c1=0;c1<NUM_CHARSETS;c1++) {
 111                 for (c2=0;c2<NUM_CHARSETS;c2++) {
 112                         if ( conv_handles[c1][c2] ) {
 113                                 smb_iconv_close( conv_handles[c1][c2] );
 114                                 conv_handles[c1][c2] = 0;
 115                         }
 116                 }
 117         }
 118         initialized = false;
 119 }
 120 
 121 /**
 122  * Initialize iconv conversion descriptors.
 123  *
 124  * This is called the first time it is needed, and also called again
 125  * every time the configuration is reloaded, because the charset or
 126  * codepage might have changed.
 127  **/
 128 void init_iconv(void)
     /* [<][>][^][v][top][bottom][index][help] */
 129 {
 130         int c1, c2;
 131         bool did_reload = False;
 132 
 133         /* so that charset_name() works we need to get the UNIX<->UCS2 going
 134            first */
 135         if (!conv_handles[CH_UNIX][CH_UTF16LE])
 136                 conv_handles[CH_UNIX][CH_UTF16LE] = smb_iconv_open(charset_name(CH_UTF16LE), "ASCII");
 137 
 138         if (!conv_handles[CH_UTF16LE][CH_UNIX])
 139                 conv_handles[CH_UTF16LE][CH_UNIX] = smb_iconv_open("ASCII", charset_name(CH_UTF16LE));
 140 
 141         for (c1=0;c1<NUM_CHARSETS;c1++) {
 142                 for (c2=0;c2<NUM_CHARSETS;c2++) {
 143                         const char *n1 = charset_name((charset_t)c1);
 144                         const char *n2 = charset_name((charset_t)c2);
 145                         if (conv_handles[c1][c2] &&
 146                             strcmp(n1, conv_handles[c1][c2]->from_name) == 0 &&
 147                             strcmp(n2, conv_handles[c1][c2]->to_name) == 0)
 148                                 continue;
 149 
 150                         did_reload = True;
 151 
 152                         if (conv_handles[c1][c2])
 153                                 smb_iconv_close(conv_handles[c1][c2]);
 154 
 155                         conv_handles[c1][c2] = smb_iconv_open(n2,n1);
 156                         if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
 157                                 DEBUG(0,("init_iconv: Conversion from %s to %s not supported\n",
 158                                          charset_name((charset_t)c1), charset_name((charset_t)c2)));
 159                                 if (c1 != CH_UTF16LE && c1 != CH_UTF16BE) {
 160                                         n1 = "ASCII";
 161                                 }
 162                                 if (c2 != CH_UTF16LE && c2 != CH_UTF16BE) {
 163                                         n2 = "ASCII";
 164                                 }
 165                                 DEBUG(0,("init_iconv: Attempting to replace with conversion from %s to %s\n",
 166                                         n1, n2 ));
 167                                 conv_handles[c1][c2] = smb_iconv_open(n2,n1);
 168                                 if (!conv_handles[c1][c2]) {
 169                                         DEBUG(0,("init_iconv: Conversion from %s to %s failed", n1, n2));
 170                                         smb_panic("init_iconv: conv_handle initialization failed");
 171                                 }
 172                         }
 173                 }
 174         }
 175 
 176         if (did_reload) {
 177                 /* XXX: Does this really get called every time the dos
 178                  * codepage changes? */
 179                 /* XXX: Is the did_reload test too strict? */
 180                 conv_silent = True;
 181                 init_valid_table();
 182                 conv_silent = False;
 183         }
 184 }
 185 
 186 /**
 187  * Convert string from one encoding to another, making error checking etc
 188  * Slow path version - uses (slow) iconv.
 189  *
 190  * @param src pointer to source string (multibyte or singlebyte)
 191  * @param srclen length of the source string in bytes
 192  * @param dest pointer to destination string (multibyte or singlebyte)
 193  * @param destlen maximal length allowed for string
 194  * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
 195  * @returns the number of bytes occupied in the destination
 196  *
 197  * Ensure the srclen contains the terminating zero.
 198  *
 199  **/
 200 
 201 static size_t convert_string_internal(charset_t from, charset_t to,
     /* [<][>][^][v][top][bottom][index][help] */
 202                       void const *src, size_t srclen, 
 203                       void *dest, size_t destlen, bool allow_bad_conv)
 204 {
 205         size_t i_len, o_len;
 206         size_t retval;
 207         const char* inbuf = (const char*)src;
 208         char* outbuf = (char*)dest;
 209         smb_iconv_t descriptor;
 210 
 211         lazy_initialize_conv();
 212 
 213         descriptor = conv_handles[from][to];
 214 
 215         if (srclen == (size_t)-1) {
 216                 if (from == CH_UTF16LE || from == CH_UTF16BE) {
 217                         srclen = (strlen_w((const smb_ucs2_t *)src)+1) * 2;
 218                 } else {
 219                         srclen = strlen((const char *)src)+1;
 220                 }
 221         }
 222 
 223 
 224         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
 225                 if (!conv_silent)
 226                         DEBUG(0,("convert_string_internal: Conversion not supported.\n"));
 227                 return (size_t)-1;
 228         }
 229 
 230         i_len=srclen;
 231         o_len=destlen;
 232 
 233  again:
 234 
 235         retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
 236         if(retval==(size_t)-1) {
 237                 const char *reason="unknown error";
 238                 switch(errno) {
 239                         case EINVAL:
 240                                 reason="Incomplete multibyte sequence";
 241                                 if (!conv_silent)
 242                                         DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
 243                                 if (allow_bad_conv)
 244                                         goto use_as_is;
 245                                 return (size_t)-1;
 246                         case E2BIG:
 247                                 reason="No more room"; 
 248                                 if (!conv_silent) {
 249                                         if (from == CH_UNIX) {
 250                                                 DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u - '%s'\n",
 251                                                         charset_name(from), charset_name(to),
 252                                                         (unsigned int)srclen, (unsigned int)destlen, (const char *)src));
 253                                         } else {
 254                                                 DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u\n",
 255                                                         charset_name(from), charset_name(to),
 256                                                         (unsigned int)srclen, (unsigned int)destlen));
 257                                         }
 258                                 }
 259                                 break;
 260                         case EILSEQ:
 261                                 reason="Illegal multibyte sequence";
 262                                 if (!conv_silent)
 263                                         DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
 264                                 if (allow_bad_conv)
 265                                         goto use_as_is;
 266                                 
 267                                 return (size_t)-1;
 268                         default:
 269                                 if (!conv_silent)
 270                                         DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
 271                                 return (size_t)-1;
 272                 }
 273                 /* smb_panic(reason); */
 274         }
 275         return destlen-o_len;
 276 
 277  use_as_is:
 278 
 279         /* 
 280          * Conversion not supported. This is actually an error, but there are so
 281          * many misconfigured iconv systems and smb.conf's out there we can't just
 282          * fail. Do a very bad conversion instead.... JRA.
 283          */
 284 
 285         {
 286                 if (o_len == 0 || i_len == 0)
 287                         return destlen - o_len;
 288 
 289                 if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) &&
 290                                 ((to != CH_UTF16LE)||(to != CH_UTF16BE))) {
 291                         /* Can't convert from utf16 any endian to multibyte.
 292                            Replace with the default fail char.
 293                         */
 294                         if (i_len < 2)
 295                                 return destlen - o_len;
 296                         if (i_len >= 2) {
 297                                 *outbuf = lp_failed_convert_char();
 298 
 299                                 outbuf++;
 300                                 o_len--;
 301 
 302                                 inbuf += 2;
 303                                 i_len -= 2;
 304                         }
 305 
 306                         if (o_len == 0 || i_len == 0)
 307                                 return destlen - o_len;
 308 
 309                         /* Keep trying with the next char... */
 310                         goto again;
 311 
 312                 } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
 313                         /* Can't convert to UTF16LE - just widen by adding the
 314                            default fail char then zero.
 315                         */
 316                         if (o_len < 2)
 317                                 return destlen - o_len;
 318 
 319                         outbuf[0] = lp_failed_convert_char();
 320                         outbuf[1] = '\0';
 321 
 322                         inbuf++;
 323                         i_len--;
 324 
 325                         outbuf += 2;
 326                         o_len -= 2;
 327 
 328                         if (o_len == 0 || i_len == 0)
 329                                 return destlen - o_len;
 330 
 331                         /* Keep trying with the next char... */
 332                         goto again;
 333 
 334                 } else if (from != CH_UTF16LE && from != CH_UTF16BE &&
 335                                 to != CH_UTF16LE && to != CH_UTF16BE) {
 336                         /* Failed multibyte to multibyte. Just copy the default fail char and
 337                                 try again. */
 338                         outbuf[0] = lp_failed_convert_char();
 339 
 340                         inbuf++;
 341                         i_len--;
 342 
 343                         outbuf++;
 344                         o_len--;
 345 
 346                         if (o_len == 0 || i_len == 0)
 347                                 return destlen - o_len;
 348 
 349                         /* Keep trying with the next char... */
 350                         goto again;
 351 
 352                 } else {
 353                         /* Keep compiler happy.... */
 354                         return destlen - o_len;
 355                 }
 356         }
 357 }
 358 
 359 /**
 360  * Convert string from one encoding to another, making error checking etc
 361  * Fast path version - handles ASCII first.
 362  *
 363  * @param src pointer to source string (multibyte or singlebyte)
 364  * @param srclen length of the source string in bytes, or -1 for nul terminated.
 365  * @param dest pointer to destination string (multibyte or singlebyte)
 366  * @param destlen maximal length allowed for string - *NEVER* -1.
 367  * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
 368  * @returns the number of bytes occupied in the destination
 369  *
 370  * Ensure the srclen contains the terminating zero.
 371  *
 372  * This function has been hand-tuned to provide a fast path.
 373  * Don't change unless you really know what you are doing. JRA.
 374  **/
 375 
 376 size_t convert_string(charset_t from, charset_t to,
     /* [<][>][^][v][top][bottom][index][help] */
 377                       void const *src, size_t srclen, 
 378                       void *dest, size_t destlen, bool allow_bad_conv)
 379 {
 380         /*
 381          * NB. We deliberately don't do a strlen here if srclen == -1.
 382          * This is very expensive over millions of calls and is taken
 383          * care of in the slow path in convert_string_internal. JRA.
 384          */
 385 
 386 #ifdef DEVELOPER
 387         SMB_ASSERT(destlen != (size_t)-1);
 388 #endif
 389 
 390         if (srclen == 0)
 391                 return 0;
 392 
 393         if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE && to != CH_UTF16BE) {
 394                 const unsigned char *p = (const unsigned char *)src;
 395                 unsigned char *q = (unsigned char *)dest;
 396                 size_t slen = srclen;
 397                 size_t dlen = destlen;
 398                 unsigned char lastp = '\0';
 399                 size_t retval = 0;
 400 
 401                 /* If all characters are ascii, fast path here. */
 402                 while (slen && dlen) {
 403                         if ((lastp = *p) <= 0x7f) {
 404                                 *q++ = *p++;
 405                                 if (slen != (size_t)-1) {
 406                                         slen--;
 407                                 }
 408                                 dlen--;
 409                                 retval++;
 410                                 if (!lastp)
 411                                         break;
 412                         } else {
 413 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
 414                                 goto general_case;
 415 #else
 416                                 size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
 417                                 if (ret == (size_t)-1) {
 418                                         return ret;
 419                                 }
 420                                 return retval + ret;
 421 #endif
 422                         }
 423                 }
 424                 if (!dlen) {
 425                         /* Even if we fast path we should note if we ran out of room. */
 426                         if (((slen != (size_t)-1) && slen) ||
 427                                         ((slen == (size_t)-1) && lastp)) {
 428                                 errno = E2BIG;
 429                         }
 430                 }
 431                 return retval;
 432         } else if (from == CH_UTF16LE && to != CH_UTF16LE) {
 433                 const unsigned char *p = (const unsigned char *)src;
 434                 unsigned char *q = (unsigned char *)dest;
 435                 size_t retval = 0;
 436                 size_t slen = srclen;
 437                 size_t dlen = destlen;
 438                 unsigned char lastp = '\0';
 439 
 440                 /* If all characters are ascii, fast path here. */
 441                 while (((slen == (size_t)-1) || (slen >= 2)) && dlen) {
 442                         if (((lastp = *p) <= 0x7f) && (p[1] == 0)) {
 443                                 *q++ = *p;
 444                                 if (slen != (size_t)-1) {
 445                                         slen -= 2;
 446                                 }
 447                                 p += 2;
 448                                 dlen--;
 449                                 retval++;
 450                                 if (!lastp)
 451                                         break;
 452                         } else {
 453 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
 454                                 goto general_case;
 455 #else
 456                                 size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
 457                                 if (ret == (size_t)-1) {
 458                                         return ret;
 459                                 }
 460                                 return retval + ret;
 461 #endif
 462                         }
 463                 }
 464                 if (!dlen) {
 465                         /* Even if we fast path we should note if we ran out of room. */
 466                         if (((slen != (size_t)-1) && slen) ||
 467                                         ((slen == (size_t)-1) && lastp)) {
 468                                 errno = E2BIG;
 469                         }
 470                 }
 471                 return retval;
 472         } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
 473                 const unsigned char *p = (const unsigned char *)src;
 474                 unsigned char *q = (unsigned char *)dest;
 475                 size_t retval = 0;
 476                 size_t slen = srclen;
 477                 size_t dlen = destlen;
 478                 unsigned char lastp = '\0';
 479 
 480                 /* If all characters are ascii, fast path here. */
 481                 while (slen && (dlen >= 2)) {
 482                         if ((lastp = *p) <= 0x7F) {
 483                                 *q++ = *p++;
 484                                 *q++ = '\0';
 485                                 if (slen != (size_t)-1) {
 486                                         slen--;
 487                                 }
 488                                 dlen -= 2;
 489                                 retval += 2;
 490                                 if (!lastp)
 491                                         break;
 492                         } else {
 493 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
 494                                 goto general_case;
 495 #else
 496                                 size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
 497                                 if (ret == (size_t)-1) {
 498                                         return ret;
 499                                 }
 500                                 return retval + ret;
 501 #endif
 502                         }
 503                 }
 504                 if (!dlen) {
 505                         /* Even if we fast path we should note if we ran out of room. */
 506                         if (((slen != (size_t)-1) && slen) ||
 507                                         ((slen == (size_t)-1) && lastp)) {
 508                                 errno = E2BIG;
 509                         }
 510                 }
 511                 return retval;
 512         }
 513 
 514 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
 515   general_case:
 516 #endif
 517         return convert_string_internal(from, to, src, srclen, dest, destlen, allow_bad_conv);
 518 }
 519 
 520 /**
 521  * Convert between character sets, allocating a new buffer for the result.
 522  *
 523  * @param ctx TALLOC_CTX to use to allocate with. If NULL use malloc.
 524  * (this is a bad interface and needs fixing. JRA).
 525  * @param srclen length of source buffer.
 526  * @param dest always set at least to NULL
 527  * @param converted_size set to the size of the allocated buffer on return
 528  * true
 529  * @note -1 is not accepted for srclen.
 530  *
 531  * @return true if new buffer was correctly allocated, and string was
 532  * converted.
 533  *
 534  * Ensure the srclen contains the terminating zero.
 535  *
 536  * I hate the goto's in this function. It's embarressing.....
 537  * There has to be a cleaner way to do this. JRA.
 538  **/
 539 
 540 bool convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
     /* [<][>][^][v][top][bottom][index][help] */
 541                              void const *src, size_t srclen, void *dst,
 542                              size_t *converted_size, bool allow_bad_conv)
 543 {
 544         size_t i_len, o_len, destlen = (srclen * 3) / 2;
 545         size_t retval;
 546         const char *inbuf = (const char *)src;
 547         char *outbuf = NULL, *ob = NULL;
 548         smb_iconv_t descriptor;
 549         void **dest = (void **)dst;
 550 
 551         *dest = NULL;
 552 
 553         if (!converted_size) {
 554                 errno = EINVAL;
 555                 return false;
 556         }
 557 
 558         if (src == NULL || srclen == (size_t)-1) {
 559                 errno = EINVAL;
 560                 return false;
 561         }
 562         if (srclen == 0) {
 563                 ob = ((ctx != NULL) ? talloc_strdup(ctx, "") : SMB_STRDUP(""));
 564                 if (ob == NULL) {
 565                         errno = ENOMEM;
 566                         return false;
 567                 }
 568                 *dest = ob;
 569                 *converted_size = 0;
 570                 return true;
 571         }
 572 
 573         lazy_initialize_conv();
 574 
 575         descriptor = conv_handles[from][to];
 576 
 577         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
 578                 if (!conv_silent)
 579                         DEBUG(0,("convert_string_allocate: Conversion not supported.\n"));
 580                 errno = EOPNOTSUPP;
 581                 return false;
 582         }
 583 
 584   convert:
 585 
 586         /* +2 is for ucs2 null termination. */
 587         if ((destlen*2)+2 < destlen) {
 588                 /* wrapped ! abort. */
 589                 if (!conv_silent)
 590                         DEBUG(0, ("convert_string_allocate: destlen wrapped !\n"));
 591                 if (!ctx)
 592                         SAFE_FREE(outbuf);
 593                 errno = EOPNOTSUPP;
 594                 return false;
 595         } else {
 596                 destlen = destlen * 2;
 597         }
 598 
 599         /* +2 is for ucs2 null termination. */
 600         if (ctx) {
 601                 ob = (char *)TALLOC_REALLOC(ctx, ob, destlen + 2);
 602         } else {
 603                 ob = (char *)SMB_REALLOC(ob, destlen + 2);
 604         }
 605 
 606         if (!ob) {
 607                 DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
 608                 errno = ENOMEM;
 609                 return false;
 610         }
 611         outbuf = ob;
 612         i_len = srclen;
 613         o_len = destlen;
 614 
 615  again:
 616 
 617         retval = smb_iconv(descriptor,
 618                            &inbuf, &i_len,
 619                            &outbuf, &o_len);
 620         if(retval == (size_t)-1)                {
 621                 const char *reason="unknown error";
 622                 switch(errno) {
 623                         case EINVAL:
 624                                 reason="Incomplete multibyte sequence";
 625                                 if (!conv_silent)
 626                                         DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
 627                                 if (allow_bad_conv)
 628                                         goto use_as_is;
 629                                 break;
 630                         case E2BIG:
 631                                 goto convert;
 632                         case EILSEQ:
 633                                 reason="Illegal multibyte sequence";
 634                                 if (!conv_silent)
 635                                         DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
 636                                 if (allow_bad_conv)
 637                                         goto use_as_is;
 638                                 break;
 639                 }
 640                 if (!conv_silent)
 641                         DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
 642                 /* smb_panic(reason); */
 643                 if (ctx) {
 644                         TALLOC_FREE(ob);
 645                 } else {
 646                         SAFE_FREE(ob);
 647                 }
 648                 return false;
 649         }
 650 
 651   out:
 652 
 653         destlen = destlen - o_len;
 654         /* Don't shrink unless we're reclaiming a lot of
 655          * space. This is in the hot codepath and these
 656          * reallocs *cost*. JRA.
 657          */
 658         if (o_len > 1024) {
 659                 /* We're shrinking here so we know the +2 is safe from wrap. */
 660                 if (ctx) {
 661                         ob = (char *)TALLOC_REALLOC(ctx,ob,destlen + 2);
 662                 } else {
 663                         ob = (char *)SMB_REALLOC(ob,destlen + 2);
 664                 }
 665         }
 666 
 667         if (destlen && !ob) {
 668                 DEBUG(0, ("convert_string_allocate: out of memory!\n"));
 669                 errno = ENOMEM;
 670                 return false;
 671         }
 672 
 673         *dest = ob;
 674 
 675         /* Must ucs2 null terminate in the extra space we allocated. */
 676         ob[destlen] = '\0';
 677         ob[destlen+1] = '\0';
 678 
 679         *converted_size = destlen;
 680         return true;
 681 
 682  use_as_is:
 683 
 684         /* 
 685          * Conversion not supported. This is actually an error, but there are so
 686          * many misconfigured iconv systems and smb.conf's out there we can't just
 687          * fail. Do a very bad conversion instead.... JRA.
 688          */
 689 
 690         {
 691                 if (o_len == 0 || i_len == 0)
 692                         goto out;
 693 
 694                 if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) &&
 695                                 ((to != CH_UTF16LE)||(to != CH_UTF16BE))) {
 696                         /* Can't convert from utf16 any endian to multibyte.
 697                            Replace with the default fail char.
 698                         */
 699 
 700                         if (i_len < 2)
 701                                 goto out;
 702 
 703                         if (i_len >= 2) {
 704                                 *outbuf = lp_failed_convert_char();
 705 
 706                                 outbuf++;
 707                                 o_len--;
 708 
 709                                 inbuf += 2;
 710                                 i_len -= 2;
 711                         }
 712 
 713                         if (o_len == 0 || i_len == 0)
 714                                 goto out;
 715 
 716                         /* Keep trying with the next char... */
 717                         goto again;
 718 
 719                 } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
 720                         /* Can't convert to UTF16LE - just widen by adding the
 721                            default fail char then zero.
 722                         */
 723                         if (o_len < 2)
 724                                 goto out;
 725 
 726                         outbuf[0] = lp_failed_convert_char();
 727                         outbuf[1] = '\0';
 728 
 729                         inbuf++;
 730                         i_len--;
 731 
 732                         outbuf += 2;
 733                         o_len -= 2;
 734 
 735                         if (o_len == 0 || i_len == 0)
 736                                 goto out;
 737 
 738                         /* Keep trying with the next char... */
 739                         goto again;
 740 
 741                 } else if (from != CH_UTF16LE && from != CH_UTF16BE &&
 742                                 to != CH_UTF16LE && to != CH_UTF16BE) {
 743                         /* Failed multibyte to multibyte. Just copy the default fail char and
 744                            try again. */
 745                         outbuf[0] = lp_failed_convert_char();
 746 
 747                         inbuf++;
 748                         i_len--;
 749 
 750                         outbuf++;
 751                         o_len--;
 752 
 753                         if (o_len == 0 || i_len == 0)
 754                                 goto out;
 755 
 756                         /* Keep trying with the next char... */
 757                         goto again;
 758 
 759                 } else {
 760                         /* Keep compiler happy.... */
 761                         goto out;
 762                 }
 763         }
 764 }
 765 
 766 /**
 767  * Convert between character sets, allocating a new buffer using talloc for the result.
 768  *
 769  * @param srclen length of source buffer.
 770  * @param dest always set at least to NULL
 771  * @parm converted_size set to the number of bytes occupied by the string in
 772  * the destination on success.
 773  * @note -1 is not accepted for srclen.
 774  *
 775  * @return true if new buffer was correctly allocated, and string was
 776  * converted.
 777  */
 778 bool convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
     /* [<][>][^][v][top][bottom][index][help] */
 779                            void const *src, size_t srclen, void *dst,
 780                            size_t *converted_size, bool allow_bad_conv)
 781 {
 782         void **dest = (void **)dst;
 783 
 784         *dest = NULL;
 785         return convert_string_allocate(ctx, from, to, src, srclen, dest,
 786                                        converted_size, allow_bad_conv);
 787 }
 788 
 789 size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
     /* [<][>][^][v][top][bottom][index][help] */
 790 {
 791         size_t size;
 792         smb_ucs2_t *buffer;
 793 
 794         if (!push_ucs2_allocate(&buffer, src, &size)) {
 795                 return (size_t)-1;
 796         }
 797 
 798         if (!strupper_w(buffer) && (dest == src)) {
 799                 free(buffer);
 800                 return srclen;
 801         }
 802 
 803         size = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, True);
 804         free(buffer);
 805         return size;
 806 }
 807 
 808 /**
 809  strdup() a unix string to upper case.
 810 **/
 811 
 812 char *strdup_upper(const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 813 {
 814         char *out_buffer = SMB_STRDUP(s);
 815         const unsigned char *p = (const unsigned char *)s;
 816         unsigned char *q = (unsigned char *)out_buffer;
 817 
 818         if (!q) {
 819                 return NULL;
 820         }
 821 
 822         /* this is quite a common operation, so we want it to be
 823            fast. We optimise for the ascii case, knowing that all our
 824            supported multi-byte character sets are ascii-compatible
 825            (ie. they match for the first 128 chars) */
 826 
 827         while (*p) {
 828                 if (*p & 0x80)
 829                         break;
 830                 *q++ = toupper_ascii_fast(*p);
 831                 p++;
 832         }
 833 
 834         if (*p) {
 835                 /* MB case. */
 836                 size_t converted_size, converted_size2;
 837                 smb_ucs2_t *buffer = NULL;
 838 
 839                 SAFE_FREE(out_buffer);
 840                 if (!convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, s,
 841                                              strlen(s) + 1,
 842                                              (void **)(void *)&buffer,
 843                                              &converted_size, True))
 844                 {
 845                         return NULL;
 846                 }
 847 
 848                 strupper_w(buffer);
 849 
 850                 if (!convert_string_allocate(NULL, CH_UTF16LE, CH_UNIX, buffer,
 851                                              converted_size,
 852                                              (void **)(void *)&out_buffer,
 853                                              &converted_size2, True))
 854                 {
 855                         TALLOC_FREE(buffer);
 856                         return NULL;
 857                 }
 858 
 859                 /* Don't need the intermediate buffer
 860                  * anymore.
 861                  */
 862                 TALLOC_FREE(buffer);
 863         }
 864 
 865         return out_buffer;
 866 }
 867 
 868 /**
 869  talloc_strdup() a unix string to upper case.
 870 **/
 871 
 872 char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 873 {
 874         char *out_buffer = talloc_strdup(ctx,s);
 875         const unsigned char *p = (const unsigned char *)s;
 876         unsigned char *q = (unsigned char *)out_buffer;
 877 
 878         if (!q) {
 879                 return NULL;
 880         }
 881 
 882         /* this is quite a common operation, so we want it to be
 883            fast. We optimise for the ascii case, knowing that all our
 884            supported multi-byte character sets are ascii-compatible
 885            (ie. they match for the first 128 chars) */
 886 
 887         while (*p) {
 888                 if (*p & 0x80)
 889                         break;
 890                 *q++ = toupper_ascii_fast(*p);
 891                 p++;
 892         }
 893 
 894         if (*p) {
 895                 /* MB case. */
 896                 size_t converted_size, converted_size2;
 897                 smb_ucs2_t *ubuf = NULL;
 898 
 899                 /* We're not using the ascii buffer above. */
 900                 TALLOC_FREE(out_buffer);
 901 
 902                 if (!convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, s,
 903                                            strlen(s)+1, (void *)&ubuf,
 904                                            &converted_size, True))
 905                 {
 906                         return NULL;
 907                 }
 908 
 909                 strupper_w(ubuf);
 910 
 911                 if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, ubuf,
 912                                            converted_size, (void *)&out_buffer,
 913                                            &converted_size2, True))
 914                 {
 915                         TALLOC_FREE(ubuf);
 916                         return NULL;
 917                 }
 918 
 919                 /* Don't need the intermediate buffer
 920                  * anymore.
 921                  */
 922                 TALLOC_FREE(ubuf);
 923         }
 924 
 925         return out_buffer;
 926 }
 927 
 928 size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
     /* [<][>][^][v][top][bottom][index][help] */
 929 {
 930         size_t size;
 931         smb_ucs2_t *buffer = NULL;
 932 
 933         if (!convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, src, srclen,
 934                                      (void **)(void *)&buffer, &size,
 935                                      True))
 936         {
 937                 smb_panic("failed to create UCS2 buffer");
 938         }
 939         if (!strlower_w(buffer) && (dest == src)) {
 940                 SAFE_FREE(buffer);
 941                 return srclen;
 942         }
 943         size = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, True);
 944         SAFE_FREE(buffer);
 945         return size;
 946 }
 947 
 948 /**
 949  strdup() a unix string to lower case.
 950 **/
 951 
 952 char *strdup_lower(const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 953 {
 954         size_t converted_size;
 955         smb_ucs2_t *buffer = NULL;
 956         char *out_buffer;
 957 
 958         if (!push_ucs2_allocate(&buffer, s, &converted_size)) {
 959                 return NULL;
 960         }
 961 
 962         strlower_w(buffer);
 963 
 964         if (!pull_ucs2_allocate(&out_buffer, buffer, &converted_size)) {
 965                 SAFE_FREE(buffer);
 966                 return NULL;
 967         }
 968 
 969         SAFE_FREE(buffer);
 970 
 971         return out_buffer;
 972 }
 973 
 974 char *talloc_strdup_lower(TALLOC_CTX *ctx, const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 975 {
 976         size_t converted_size;
 977         smb_ucs2_t *buffer = NULL;
 978         char *out_buffer;
 979 
 980         if (!push_ucs2_talloc(ctx, &buffer, s, &converted_size)) {
 981                 return NULL;
 982         }
 983 
 984         strlower_w(buffer);
 985 
 986         if (!pull_ucs2_talloc(ctx, &out_buffer, buffer, &converted_size)) {
 987                 TALLOC_FREE(buffer);
 988                 return NULL;
 989         }
 990 
 991         TALLOC_FREE(buffer);
 992 
 993         return out_buffer;
 994 }
 995 
 996 
 997 size_t ucs2_align(const void *base_ptr, const void *p, int flags)
     /* [<][>][^][v][top][bottom][index][help] */
 998 {
 999         if (flags & (STR_NOALIGN|STR_ASCII))
1000                 return 0;
1001         return PTR_DIFF(p, base_ptr) & 1;
1002 }
1003 
1004 
1005 /**
1006  * Copy a string from a char* unix src to a dos codepage string destination.
1007  *
1008  * @return the number of bytes occupied by the string in the destination.
1009  *
1010  * @param flags can include
1011  * <dl>
1012  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
1013  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
1014  * </dl>
1015  *
1016  * @param dest_len the maximum length in bytes allowed in the
1017  * destination.
1018  **/
1019 size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
     /* [<][>][^][v][top][bottom][index][help] */
1020 {
1021         size_t src_len = strlen(src);
1022         char *tmpbuf = NULL;
1023         size_t ret;
1024 
1025         /* No longer allow a length of -1. */
1026         if (dest_len == (size_t)-1) {
1027                 smb_panic("push_ascii - dest_len == -1");
1028         }
1029 
1030         if (flags & STR_UPPER) {
1031                 tmpbuf = SMB_STRDUP(src);
1032                 if (!tmpbuf) {
1033                         smb_panic("malloc fail");
1034                 }
1035                 strupper_m(tmpbuf);
1036                 src = tmpbuf;
1037         }
1038 
1039         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
1040                 src_len++;
1041         }
1042 
1043         ret = convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, True);
1044         if (ret == (size_t)-1 &&
1045                         (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
1046                         && dest_len > 0) {
1047                 ((char *)dest)[0] = '\0';
1048         }
1049         SAFE_FREE(tmpbuf);
1050         return ret;
1051 }
1052 
1053 size_t push_ascii_fstring(void *dest, const char *src)
     /* [<][>][^][v][top][bottom][index][help] */
1054 {
1055         return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
1056 }
1057 
1058 /********************************************************************
1059  Push an nstring - ensure null terminated. Written by
1060  moriyama@miraclelinux.com (MORIYAMA Masayuki).
1061 ********************************************************************/
1062 
1063 size_t push_ascii_nstring(void *dest, const char *src)
     /* [<][>][^][v][top][bottom][index][help] */
1064 {
1065         size_t i, buffer_len, dest_len;
1066         smb_ucs2_t *buffer;
1067 
1068         conv_silent = True;
1069         if (!push_ucs2_allocate(&buffer, src, &buffer_len)) {
1070                 smb_panic("failed to create UCS2 buffer");
1071         }
1072 
1073         /* We're using buffer_len below to count ucs2 characters, not bytes. */
1074         buffer_len /= sizeof(smb_ucs2_t);
1075 
1076         dest_len = 0;
1077         for (i = 0; buffer[i] != 0 && (i < buffer_len); i++) {
1078                 unsigned char mb[10];
1079                 /* Convert one smb_ucs2_t character at a time. */
1080                 size_t mb_len = convert_string(CH_UTF16LE, CH_DOS, buffer+i, sizeof(smb_ucs2_t), mb, sizeof(mb), False);
1081                 if ((mb_len != (size_t)-1) && (dest_len + mb_len <= MAX_NETBIOSNAME_LEN - 1)) {
1082                         memcpy((char *)dest + dest_len, mb, mb_len);
1083                         dest_len += mb_len;
1084                 } else {
1085                         errno = E2BIG;
1086                         break;
1087                 }
1088         }
1089         ((char *)dest)[dest_len] = '\0';
1090 
1091         SAFE_FREE(buffer);
1092         conv_silent = False;
1093         return dest_len;
1094 }
1095 
1096 /********************************************************************
1097  Push and malloc an ascii string. src and dest null terminated.
1098 ********************************************************************/
1099 
1100 bool push_ascii_allocate(char **dest, const char *src, size_t *converted_size)
     /* [<][>][^][v][top][bottom][index][help] */
1101 {
1102         size_t src_len = strlen(src)+1;
1103 
1104         *dest = NULL;
1105         return convert_string_allocate(NULL, CH_UNIX, CH_DOS, src, src_len,
1106                                        (void **)dest, converted_size, True);
1107 }
1108 
1109 /**
1110  * Copy a string from a dos codepage source to a unix char* destination.
1111  *
1112  * The resulting string in "dest" is always null terminated.
1113  *
1114  * @param flags can have:
1115  * <dl>
1116  * <dt>STR_TERMINATE</dt>
1117  * <dd>STR_TERMINATE means the string in @p src
1118  * is null terminated, and src_len is ignored.</dd>
1119  * </dl>
1120  *
1121  * @param src_len is the length of the source area in bytes.
1122  * @returns the number of bytes occupied by the string in @p src.
1123  **/
1124 size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
     /* [<][>][^][v][top][bottom][index][help] */
1125 {
1126         size_t ret;
1127 
1128         if (dest_len == (size_t)-1) {
1129                 /* No longer allow dest_len of -1. */
1130                 smb_panic("pull_ascii - invalid dest_len of -1");
1131         }
1132 
1133         if (flags & STR_TERMINATE) {
1134                 if (src_len == (size_t)-1) {
1135                         src_len = strlen((const char *)src) + 1;
1136                 } else {
1137                         size_t len = strnlen((const char *)src, src_len);
1138                         if (len < src_len)
1139                                 len++;
1140                         src_len = len;
1141                 }
1142         }
1143 
1144         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, True);
1145         if (ret == (size_t)-1) {
1146                 ret = 0;
1147                 dest_len = 0;
1148         }
1149 
1150         if (dest_len && ret) {
1151                 /* Did we already process the terminating zero ? */
1152                 if (dest[MIN(ret-1, dest_len-1)] != 0) {
1153                         dest[MIN(ret, dest_len-1)] = 0;
1154                 }
1155         } else  {
1156                 dest[0] = 0;
1157         }
1158 
1159         return src_len;
1160 }
1161 
1162 /**
1163  * Copy a string from a dos codepage source to a unix char* destination.
1164  Talloc version.
1165  Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
1166  needs fixing. JRA).
1167  *
1168  * The resulting string in "dest" is always null terminated.
1169  *
1170  * @param flags can have:
1171  * <dl>
1172  * <dt>STR_TERMINATE</dt>
1173  * <dd>STR_TERMINATE means the string in @p src
1174  * is null terminated, and src_len is ignored.</dd>
1175  * </dl>
1176  *
1177  * @param src_len is the length of the source area in bytes.
1178  * @returns the number of bytes occupied by the string in @p src.
1179  **/
1180 
1181 static size_t pull_ascii_base_talloc(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1182                                         char **ppdest,
1183                                         const void *src,
1184                                         size_t src_len,
1185                                         int flags)
1186 {
1187         char *dest = NULL;
1188         size_t dest_len;
1189 
1190 #ifdef DEVELOPER
1191         /* Ensure we never use the braindead "malloc" varient. */
1192         if (ctx == NULL) {
1193                 smb_panic("NULL talloc CTX in pull_ascii_base_talloc\n");
1194         }
1195 #endif
1196 
1197         *ppdest = NULL;
1198 
1199         if (!src_len) {
1200                 return 0;
1201         }
1202 
1203         if (flags & STR_TERMINATE) {
1204                 if (src_len == (size_t)-1) {
1205                         src_len = strlen((const char *)src) + 1;
1206                 } else {
1207                         size_t len = strnlen((const char *)src, src_len);
1208                         if (len < src_len)
1209                                 len++;
1210                         src_len = len;
1211                 }
1212                 /* Ensure we don't use an insane length from the client. */
1213                 if (src_len >= 1024*1024) {
1214                         char *msg = talloc_asprintf(ctx,
1215                                         "Bad src length (%u) in "
1216                                         "pull_ascii_base_talloc",
1217                                         (unsigned int)src_len);
1218                         smb_panic(msg);
1219                 }
1220         } else {
1221                 /* Can't have an unlimited length
1222                  * non STR_TERMINATE'd.
1223                  */
1224                 if (src_len == (size_t)-1) {
1225                         errno = EINVAL;
1226                         return 0;
1227                 }
1228         }
1229 
1230         /* src_len != -1 here. */
1231 
1232         if (!convert_string_allocate(ctx, CH_DOS, CH_UNIX, src, src_len, &dest,
1233                                      &dest_len, True)) {
1234                 dest_len = 0;
1235         }
1236 
1237         if (dest_len && dest) {
1238                 /* Did we already process the terminating zero ? */
1239                 if (dest[dest_len-1] != 0) {
1240                         size_t size = talloc_get_size(dest);
1241                         /* Have we got space to append the '\0' ? */
1242                         if (size <= dest_len) {
1243                                 /* No, realloc. */
1244                                 dest = TALLOC_REALLOC_ARRAY(ctx, dest, char,
1245                                                 dest_len+1);
1246                                 if (!dest) {
1247                                         /* talloc fail. */
1248                                         dest_len = (size_t)-1;
1249                                         return 0;
1250                                 }
1251                         }
1252                         /* Yay - space ! */
1253                         dest[dest_len] = '\0';
1254                         dest_len++;
1255                 }
1256         } else if (dest) {
1257                 dest[0] = 0;
1258         }
1259 
1260         *ppdest = dest;
1261         return src_len;
1262 }
1263 
1264 size_t pull_ascii_fstring(char *dest, const void *src)
     /* [<][>][^][v][top][bottom][index][help] */
1265 {
1266         return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
1267 }
1268 
1269 /* When pulling an nstring it can expand into a larger size (dos cp -> utf8). Cope with this. */
1270 
1271 size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src)
     /* [<][>][^][v][top][bottom][index][help] */
1272 {
1273         return pull_ascii(dest, src, dest_len, sizeof(nstring)-1, STR_TERMINATE);
1274 }
1275 
1276 /**
1277  * Copy a string from a char* src to a unicode destination.
1278  *
1279  * @returns the number of bytes occupied by the string in the destination.
1280  *
1281  * @param flags can have:
1282  *
1283  * <dl>
1284  * <dt>STR_TERMINATE <dd>means include the null termination.
1285  * <dt>STR_UPPER     <dd>means uppercase in the destination.
1286  * <dt>STR_NOALIGN   <dd>means don't do alignment.
1287  * </dl>
1288  *
1289  * @param dest_len is the maximum length allowed in the
1290  * destination.
1291  **/
1292 
1293 size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
     /* [<][>][^][v][top][bottom][index][help] */
1294 {
1295         size_t len=0;
1296         size_t src_len;
1297         size_t ret;
1298 
1299         if (dest_len == (size_t)-1) {
1300                 /* No longer allow dest_len of -1. */
1301                 smb_panic("push_ucs2 - invalid dest_len of -1");
1302         }
1303 
1304         if (flags & STR_TERMINATE)
1305                 src_len = (size_t)-1;
1306         else
1307                 src_len = strlen(src);
1308 
1309         if (ucs2_align(base_ptr, dest, flags)) {
1310                 *(char *)dest = 0;
1311                 dest = (void *)((char *)dest + 1);
1312                 if (dest_len)
1313                         dest_len--;
1314                 len++;
1315         }
1316 
1317         /* ucs2 is always a multiple of 2 bytes */
1318         dest_len &= ~1;
1319 
1320         ret =  convert_string(CH_UNIX, CH_UTF16LE, src, src_len, dest, dest_len, True);
1321         if (ret == (size_t)-1) {
1322                 if ((flags & STR_TERMINATE) &&
1323                                 dest &&
1324                                 dest_len) {
1325                         *(char *)dest = 0;
1326                 }
1327                 return len;
1328         }
1329 
1330         len += ret;
1331 
1332         if (flags & STR_UPPER) {
1333                 smb_ucs2_t *dest_ucs2 = (smb_ucs2_t *)dest;
1334                 size_t i;
1335 
1336                 /* We check for i < (ret / 2) below as the dest string isn't null
1337                    terminated if STR_TERMINATE isn't set. */
1338 
1339                 for (i = 0; i < (ret / 2) && i < (dest_len / 2) && dest_ucs2[i]; i++) {
1340                         smb_ucs2_t v = toupper_w(dest_ucs2[i]);
1341                         if (v != dest_ucs2[i]) {
1342                                 dest_ucs2[i] = v;
1343                         }
1344                 }
1345         }
1346 
1347         return len;
1348 }
1349 
1350 
1351 /**
1352  * Copy a string from a unix char* src to a UCS2 destination,
1353  * allocating a buffer using talloc().
1354  *
1355  * @param dest always set at least to NULL 
1356  * @parm converted_size set to the number of bytes occupied by the string in
1357  * the destination on success.
1358  *
1359  * @return true if new buffer was correctly allocated, and string was
1360  * converted.
1361  **/
1362 bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src,
     /* [<][>][^][v][top][bottom][index][help] */
1363                       size_t *converted_size)
1364 {
1365         size_t src_len = strlen(src)+1;
1366 
1367         *dest = NULL;
1368         return convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, src, src_len,
1369                                      (void **)dest, converted_size, True);
1370 }
1371 
1372 
1373 /**
1374  * Copy a string from a unix char* src to a UCS2 destination, allocating a buffer
1375  *
1376  * @param dest always set at least to NULL 
1377  * @parm converted_size set to the number of bytes occupied by the string in
1378  * the destination on success.
1379  *
1380  * @return true if new buffer was correctly allocated, and string was
1381  * converted.
1382  **/
1383 
1384 bool push_ucs2_allocate(smb_ucs2_t **dest, const char *src,
     /* [<][>][^][v][top][bottom][index][help] */
1385                         size_t *converted_size)
1386 {
1387         size_t src_len = strlen(src)+1;
1388 
1389         *dest = NULL;
1390         return convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, src, src_len,
1391                                        (void **)dest, converted_size, True);
1392 }
1393 
1394 /**
1395  Copy a string from a char* src to a UTF-8 destination.
1396  Return the number of bytes occupied by the string in the destination
1397  Flags can have:
1398   STR_TERMINATE means include the null termination
1399   STR_UPPER     means uppercase in the destination
1400  dest_len is the maximum length allowed in the destination. If dest_len
1401  is -1 then no maxiumum is used.
1402 **/
1403 
1404 static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
     /* [<][>][^][v][top][bottom][index][help] */
1405 {
1406         size_t src_len = 0;
1407         size_t ret;
1408         char *tmpbuf = NULL;
1409 
1410         if (dest_len == (size_t)-1) {
1411                 /* No longer allow dest_len of -1. */
1412                 smb_panic("push_utf8 - invalid dest_len of -1");
1413         }
1414 
1415         if (flags & STR_UPPER) {
1416                 tmpbuf = strdup_upper(src);
1417                 if (!tmpbuf) {
1418                         return (size_t)-1;
1419                 }
1420                 src = tmpbuf;
1421                 src_len = strlen(src);
1422         }
1423 
1424         src_len = strlen(src);
1425         if (flags & STR_TERMINATE) {
1426                 src_len++;
1427         }
1428 
1429         ret = convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len, True);
1430         SAFE_FREE(tmpbuf);
1431         return ret;
1432 }
1433 
1434 size_t push_utf8_fstring(void *dest, const char *src)
     /* [<][>][^][v][top][bottom][index][help] */
1435 {
1436         return push_utf8(dest, src, sizeof(fstring), STR_TERMINATE);
1437 }
1438 
1439 /**
1440  * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
1441  *
1442  * @param dest always set at least to NULL 
1443  * @parm converted_size set to the number of bytes occupied by the string in
1444  * the destination on success.
1445  *
1446  * @return true if new buffer was correctly allocated, and string was
1447  * converted.
1448  **/
1449 
1450 bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
     /* [<][>][^][v][top][bottom][index][help] */
1451                       size_t *converted_size)
1452 {
1453         size_t src_len = strlen(src)+1;
1454 
1455         *dest = NULL;
1456         return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len,
1457                                      (void**)dest, converted_size, True);
1458 }
1459 
1460 /**
1461  * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer
1462  *
1463  * @param dest always set at least to NULL 
1464  * @parm converted_size set to the number of bytes occupied by the string in
1465  * the destination on success.
1466  *
1467  * @return true if new buffer was correctly allocated, and string was
1468  * converted.
1469  **/
1470 
1471 bool push_utf8_allocate(char **dest, const char *src, size_t *converted_size)
     /* [<][>][^][v][top][bottom][index][help] */
1472 {
1473         size_t src_len = strlen(src)+1;
1474 
1475         *dest = NULL;
1476         return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len,
1477                                        (void **)dest, converted_size, True);
1478 }
1479 
1480 /**
1481  Copy a string from a ucs2 source to a unix char* destination.
1482  Flags can have:
1483   STR_TERMINATE means the string in src is null terminated.
1484   STR_NOALIGN   means don't try to align.
1485  if STR_TERMINATE is set then src_len is ignored if it is -1.
1486  src_len is the length of the source area in bytes
1487  Return the number of bytes occupied by the string in src.
1488  The resulting string in "dest" is always null terminated.
1489 **/
1490 
1491 size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
     /* [<][>][^][v][top][bottom][index][help] */
1492 {
1493         size_t ret;
1494 
1495         if (dest_len == (size_t)-1) {
1496                 /* No longer allow dest_len of -1. */
1497                 smb_panic("pull_ucs2 - invalid dest_len of -1");
1498         }
1499 
1500         if (!src_len) {
1501                 if (dest && dest_len > 0) {
1502                         dest[0] = '\0';
1503                 }
1504                 return 0;
1505         }
1506 
1507         if (ucs2_align(base_ptr, src, flags)) {
1508                 src = (const void *)((const char *)src + 1);
1509                 if (src_len != (size_t)-1)
1510                         src_len--;
1511         }
1512 
1513         if (flags & STR_TERMINATE) {
1514                 /* src_len -1 is the default for null terminated strings. */
1515                 if (src_len != (size_t)-1) {
1516                         size_t len = strnlen_w((const smb_ucs2_t *)src,
1517                                                 src_len/2);
1518                         if (len < src_len/2)
1519                                 len++;
1520                         src_len = len*2;
1521                 }
1522         }
1523 
1524         /* ucs2 is always a multiple of 2 bytes */
1525         if (src_len != (size_t)-1)
1526                 src_len &= ~1;
1527 
1528         ret = convert_string(CH_UTF16LE, CH_UNIX, src, src_len, dest, dest_len, True);
1529         if (ret == (size_t)-1) {
1530                 ret = 0;
1531                 dest_len = 0;
1532         }
1533 
1534         if (src_len == (size_t)-1)
1535                 src_len = ret*2;
1536 
1537         if (dest_len && ret) {
1538                 /* Did we already process the terminating zero ? */
1539                 if (dest[MIN(ret-1, dest_len-1)] != 0) {
1540                         dest[MIN(ret, dest_len-1)] = 0;
1541                 }
1542         } else {
1543                 dest[0] = 0;
1544         }
1545 
1546         return src_len;
1547 }
1548 
1549 /**
1550  Copy a string from a ucs2 source to a unix char* destination.
1551  Talloc version with a base pointer.
1552  Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
1553  needs fixing. JRA).
1554  Flags can have:
1555   STR_TERMINATE means the string in src is null terminated.
1556   STR_NOALIGN   means don't try to align.
1557  if STR_TERMINATE is set then src_len is ignored if it is -1.
1558  src_len is the length of the source area in bytes
1559  Return the number of bytes occupied by the string in src.
1560  The resulting string in "dest" is always null terminated.
1561 **/
1562 
1563 size_t pull_ucs2_base_talloc(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1564                         const void *base_ptr,
1565                         char **ppdest,
1566                         const void *src,
1567                         size_t src_len,
1568                         int flags)
1569 {
1570         char *dest;
1571         size_t dest_len;
1572 
1573         *ppdest = NULL;
1574 
1575 #ifdef DEVELOPER
1576         /* Ensure we never use the braindead "malloc" varient. */
1577         if (ctx == NULL) {
1578                 smb_panic("NULL talloc CTX in pull_ucs2_base_talloc\n");
1579         }
1580 #endif
1581 
1582         if (!src_len) {
1583                 return 0;
1584         }
1585 
1586         if (ucs2_align(base_ptr, src, flags)) {
1587                 src = (const void *)((const char *)src + 1);
1588                 if (src_len != (size_t)-1)
1589                         src_len--;
1590         }
1591 
1592         if (flags & STR_TERMINATE) {
1593                 /* src_len -1 is the default for null terminated strings. */
1594                 if (src_len != (size_t)-1) {
1595                         size_t len = strnlen_w((const smb_ucs2_t *)src,
1596                                                 src_len/2);
1597                         if (len < src_len/2)
1598                                 len++;
1599                         src_len = len*2;
1600                 } else {
1601                         /*
1602                          * src_len == -1 - alloc interface won't take this
1603                          * so we must calculate.
1604                          */
1605                         src_len = (strlen_w((const smb_ucs2_t *)src)+1)*sizeof(smb_ucs2_t);
1606                 }
1607                 /* Ensure we don't use an insane length from the client. */
1608                 if (src_len >= 1024*1024) {
1609                         smb_panic("Bad src length in pull_ucs2_base_talloc\n");
1610                 }
1611         } else {
1612                 /* Can't have an unlimited length
1613                  * non STR_TERMINATE'd.
1614                  */
1615                 if (src_len == (size_t)-1) {
1616                         errno = EINVAL;
1617                         return 0;
1618                 }
1619         }
1620 
1621         /* src_len != -1 here. */
1622 
1623         /* ucs2 is always a multiple of 2 bytes */
1624         src_len &= ~1;
1625 
1626         if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
1627                                    (void *)&dest, &dest_len, True)) {
1628                 dest_len = 0;
1629         }
1630 
1631         if (dest_len) {
1632                 /* Did we already process the terminating zero ? */
1633                 if (dest[dest_len-1] != 0) {
1634                         size_t size = talloc_get_size(dest);
1635                         /* Have we got space to append the '\0' ? */
1636                         if (size <= dest_len) {
1637                                 /* No, realloc. */
1638                                 dest = TALLOC_REALLOC_ARRAY(ctx, dest, char,
1639                                                 dest_len+1);
1640                                 if (!dest) {
1641                                         /* talloc fail. */
1642                                         dest_len = (size_t)-1;
1643                                         return 0;
1644                                 }
1645                         }
1646                         /* Yay - space ! */
1647                         dest[dest_len] = '\0';
1648                         dest_len++;
1649                 }
1650         } else if (dest) {
1651                 dest[0] = 0;
1652         }
1653 
1654         *ppdest = dest;
1655         return src_len;
1656 }
1657 
1658 size_t pull_ucs2_fstring(char *dest, const void *src)
     /* [<][>][^][v][top][bottom][index][help] */
1659 {
1660         return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
1661 }
1662 
1663 /**
1664  * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
1665  *
1666  * @param dest always set at least to NULL 
1667  * @parm converted_size set to the number of bytes occupied by the string in
1668  * the destination on success.
1669  *
1670  * @return true if new buffer was correctly allocated, and string was
1671  * converted.
1672  **/
1673 
1674 bool pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src,
     /* [<][>][^][v][top][bottom][index][help] */
1675                       size_t *converted_size)
1676 {
1677         size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
1678 
1679         *dest = NULL;
1680         return convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
1681                                      (void **)dest, converted_size, True);
1682 }
1683 
1684 /**
1685  * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer
1686  *
1687  * @param dest always set at least to NULL 
1688  * @parm converted_size set to the number of bytes occupied by the string in
1689  * the destination on success.
1690  * @return true if new buffer was correctly allocated, and string was
1691  * converted.
1692  **/
1693 
1694 bool pull_ucs2_allocate(char **dest, const smb_ucs2_t *src,
     /* [<][>][^][v][top][bottom][index][help] */
1695                         size_t *converted_size)
1696 {
1697         size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
1698 
1699         *dest = NULL;
1700         return convert_string_allocate(NULL, CH_UTF16LE, CH_UNIX, src, src_len,
1701                                        (void **)dest, converted_size, True);
1702 }
1703 
1704 /**
1705  * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
1706  *
1707  * @param dest always set at least to NULL 
1708  * @parm converted_size set to the number of bytes occupied by the string in
1709  * the destination on success.
1710  *
1711  * @return true if new buffer was correctly allocated, and string was
1712  * converted.
1713  **/
1714 
1715 bool pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
     /* [<][>][^][v][top][bottom][index][help] */
1716                       size_t *converted_size)
1717 {
1718         size_t src_len = strlen(src)+1;
1719 
1720         *dest = NULL;
1721         return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len,
1722                                      (void **)dest, converted_size, True);
1723 }
1724 
1725 /**
1726  * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer
1727  *
1728  * @param dest always set at least to NULL 
1729  * @parm converted_size set to the number of bytes occupied by the string in
1730  * the destination on success.
1731  *
1732  * @return true if new buffer was correctly allocated, and string was
1733  * converted.
1734  **/
1735 
1736 bool pull_utf8_allocate(char **dest, const char *src, size_t *converted_size)
     /* [<][>][^][v][top][bottom][index][help] */
1737 {
1738         size_t src_len = strlen(src)+1;
1739 
1740         *dest = NULL;
1741         return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len,
1742                                        (void **)dest, converted_size, True);
1743 }
1744  
1745 /**
1746  * Copy a string from a DOS src to a unix char * destination, allocating a buffer using talloc
1747  *
1748  * @param dest always set at least to NULL 
1749  * @parm converted_size set to the number of bytes occupied by the string in
1750  * the destination on success.
1751  *
1752  * @return true if new buffer was correctly allocated, and string was
1753  * converted.
1754  **/
1755 
1756 bool pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
     /* [<][>][^][v][top][bottom][index][help] */
1757                        size_t *converted_size)
1758 {
1759         size_t src_len = strlen(src)+1;
1760 
1761         *dest = NULL;
1762         return convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len,
1763                                      (void **)dest, converted_size, True);
1764 }
1765 
1766 /**
1767  Copy a string from a char* src to a unicode or ascii
1768  dos codepage destination choosing unicode or ascii based on the 
1769  flags in the SMB buffer starting at base_ptr.
1770  Return the number of bytes occupied by the string in the destination.
1771  flags can have:
1772   STR_TERMINATE means include the null termination.
1773   STR_UPPER     means uppercase in the destination.
1774   STR_ASCII     use ascii even with unicode packet.
1775   STR_NOALIGN   means don't do alignment.
1776  dest_len is the maximum length allowed in the destination. If dest_len
1777  is -1 then no maxiumum is used.
1778 **/
1779 
1780 size_t push_string_fn(const char *function, unsigned int line,
     /* [<][>][^][v][top][bottom][index][help] */
1781                       const void *base_ptr, uint16 flags2,
1782                       void *dest, const char *src,
1783                       size_t dest_len, int flags)
1784 {
1785 #ifdef DEVELOPER
1786         /* We really need to zero fill here, not clobber
1787          * region, as we want to ensure that valgrind thinks
1788          * all of the outgoing buffer has been written to
1789          * so a send() or write() won't trap an error.
1790          * JRA.
1791          */
1792 #if 0
1793         clobber_region(function, line, dest, dest_len);
1794 #else
1795         memset(dest, '\0', dest_len);
1796 #endif
1797 #endif
1798 
1799         if (!(flags & STR_ASCII) && \
1800             ((flags & STR_UNICODE || \
1801               (flags2 & FLAGS2_UNICODE_STRINGS)))) {
1802                 return push_ucs2(base_ptr, dest, src, dest_len, flags);
1803         }
1804         return push_ascii(dest, src, dest_len, flags);
1805 }
1806 
1807 
1808 /**
1809  Copy a string from a unicode or ascii source (depending on
1810  the packet flags) to a char* destination.
1811  Flags can have:
1812   STR_TERMINATE means the string in src is null terminated.
1813   STR_UNICODE   means to force as unicode.
1814   STR_ASCII     use ascii even with unicode packet.
1815   STR_NOALIGN   means don't do alignment.
1816  if STR_TERMINATE is set then src_len is ignored is it is -1
1817  src_len is the length of the source area in bytes.
1818  Return the number of bytes occupied by the string in src.
1819  The resulting string in "dest" is always null terminated.
1820 **/
1821 
1822 size_t pull_string_fn(const char *function,
     /* [<][>][^][v][top][bottom][index][help] */
1823                         unsigned int line,
1824                         const void *base_ptr,
1825                         uint16 smb_flags2,
1826                         char *dest,
1827                         const void *src,
1828                         size_t dest_len,
1829                         size_t src_len,
1830                         int flags)
1831 {
1832 #ifdef DEVELOPER
1833         clobber_region(function, line, dest, dest_len);
1834 #endif
1835 
1836         if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
1837                 smb_panic("No base ptr to get flg2 and neither ASCII nor "
1838                           "UNICODE defined");
1839         }
1840 
1841         if (!(flags & STR_ASCII) && \
1842             ((flags & STR_UNICODE || \
1843               (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
1844                 return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
1845         }
1846         return pull_ascii(dest, src, dest_len, src_len, flags);
1847 }
1848 
1849 /**
1850  Copy a string from a unicode or ascii source (depending on
1851  the packet flags) to a char* destination.
1852  Variant that uses talloc.
1853  Flags can have:
1854   STR_TERMINATE means the string in src is null terminated.
1855   STR_UNICODE   means to force as unicode.
1856   STR_ASCII     use ascii even with unicode packet.
1857   STR_NOALIGN   means don't do alignment.
1858  if STR_TERMINATE is set then src_len is ignored is it is -1
1859  src_len is the length of the source area in bytes.
1860  Return the number of bytes occupied by the string in src.
1861  The resulting string in "dest" is always null terminated.
1862 **/
1863 
1864 size_t pull_string_talloc_fn(const char *function,
     /* [<][>][^][v][top][bottom][index][help] */
1865                         unsigned int line,
1866                         TALLOC_CTX *ctx,
1867                         const void *base_ptr,
1868                         uint16 smb_flags2,
1869                         char **ppdest,
1870                         const void *src,
1871                         size_t src_len,
1872                         int flags)
1873 {
1874         if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
1875                 smb_panic("No base ptr to get flg2 and neither ASCII nor "
1876                           "UNICODE defined");
1877         }
1878 
1879         if (!(flags & STR_ASCII) && \
1880             ((flags & STR_UNICODE || \
1881               (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
1882                 return pull_ucs2_base_talloc(ctx,
1883                                         base_ptr,
1884                                         ppdest,
1885                                         src,
1886                                         src_len,
1887                                         flags);
1888         }
1889         return pull_ascii_base_talloc(ctx,
1890                                         ppdest,
1891                                         src,
1892                                         src_len,
1893                                         flags);
1894 }
1895 
1896 
1897 size_t align_string(const void *base_ptr, const char *p, int flags)
     /* [<][>][^][v][top][bottom][index][help] */
1898 {
1899         if (!(flags & STR_ASCII) && \
1900             ((flags & STR_UNICODE || \
1901               (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
1902                 return ucs2_align(base_ptr, p, flags);
1903         }
1904         return 0;
1905 }
1906 
1907 /*
1908   Return the unicode codepoint for the next multi-byte CH_UNIX character
1909   in the string. The unicode codepoint (codepoint_t) is an unsinged 32 bit value.
1910 
1911   Also return the number of bytes consumed (which tells the caller
1912   how many bytes to skip to get to the next CH_UNIX character).
1913 
1914   Return INVALID_CODEPOINT if the next character cannot be converted.
1915 */
1916 
1917 codepoint_t next_codepoint(const char *str, size_t *size)
     /* [<][>][^][v][top][bottom][index][help] */
1918 {
1919         /* It cannot occupy more than 4 bytes in UTF16 format */
1920         uint8_t buf[4];
1921         smb_iconv_t descriptor;
1922         size_t ilen_orig;
1923         size_t ilen;
1924         size_t olen;
1925         char *outbuf;
1926 
1927         if ((str[0] & 0x80) == 0) {
1928                 *size = 1;
1929                 return (codepoint_t)str[0];
1930         }
1931 
1932         /* We assume that no multi-byte character can take
1933            more than 5 bytes. This is OK as we only
1934            support codepoints up to 1M */
1935 
1936         ilen_orig = strnlen(str, 5);
1937         ilen = ilen_orig;
1938 
1939         lazy_initialize_conv();
1940 
1941         descriptor = conv_handles[CH_UNIX][CH_UTF16LE];
1942         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
1943                 *size = 1;
1944                 return INVALID_CODEPOINT;
1945         }
1946 
1947         /* This looks a little strange, but it is needed to cope
1948            with codepoints above 64k which are encoded as per RFC2781. */
1949         olen = 2;
1950         outbuf = (char *)buf;
1951         smb_iconv(descriptor, &str, &ilen, &outbuf, &olen);
1952         if (olen == 2) {
1953                 /* We failed to convert to a 2 byte character.
1954                    See if we can convert to a 4 UTF16-LE byte char encoding.
1955                 */
1956                 olen = 4;
1957                 outbuf = (char *)buf;
1958                 smb_iconv(descriptor,  &str, &ilen, &outbuf, &olen);
1959                 if (olen == 4) {
1960                         /* We didn't convert any bytes */
1961                         *size = 1;
1962                         return INVALID_CODEPOINT;
1963                 }
1964                 olen = 4 - olen;
1965         } else {
1966                 olen = 2 - olen;
1967         }
1968 
1969         *size = ilen_orig - ilen;
1970 
1971         if (olen == 2) {
1972                 /* 2 byte, UTF16-LE encoded value. */
1973                 return (codepoint_t)SVAL(buf, 0);
1974         }
1975         if (olen == 4) {
1976                 /* Decode a 4 byte UTF16-LE character manually.
1977                    See RFC2871 for the encoding machanism.
1978                 */
1979                 codepoint_t w1 = SVAL(buf,0) & ~0xD800;
1980                 codepoint_t w2 = SVAL(buf,2) & ~0xDC00;
1981 
1982                 return (codepoint_t)0x10000 +
1983                                 (w1 << 10) + w2;
1984         }
1985 
1986         /* no other length is valid */
1987         return INVALID_CODEPOINT;
1988 }

/* [<][>][^][v][top][bottom][index][help] */