old fixes I forgot to commit
[sfrench/samba-autobuild/.git] / source3 / lib / util_unistr.c
index ddcea26e38945bd1945353ea96312eb7510afe2d..7d690ecb9c6e011e3eb74788aa6c367c07deae94 100644 (file)
@@ -1,8 +1,8 @@
 /* 
    Unix SMB/Netbios implementation.
-   Version 1.9.
+   Version 3.0
    Samba utility functions
-   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Andrew Tridgell 1992-2001
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
-
-/*
- * The following are the codepage to ucs2 and vica versa maps.
- * These are dynamically loaded from a unicode translation file.
- */
-
-static smb_ucs2_t *doscp_to_ucs2;
-static uint16 *ucs2_to_doscp;
-
-static smb_ucs2_t *unixcp_to_ucs2;
-static uint16 *ucs2_to_unixcp;
-
 #ifndef MAXUNI
 #define MAXUNI 1024
 #endif
 
-/*******************************************************************
- Write a string in (little-endian) unicode format. src is in
- the current DOS codepage. len is the length in bytes of the
- string pointed to by dst.
-
- the return value is the length of the string *without* the trailing 
- two bytes of zero
-********************************************************************/
-
-int dos_PutUniCode(char *dst,const char *src, ssize_t len)
-{
-       int ret = 0;
-       while (*src && (len > 2)) {
-               size_t skip = skip_multibyte_char(*src);
-               smb_ucs2_t val = (*src & 0xff);
-
-               /*
-                * If this is a multibyte character (and all DOS/Windows
-                * codepages have at maximum 2 byte multibyte characters)
-                * then work out the index value for the unicode conversion.
-                */
-
-               if (skip == 2)
-                       val = ((val << 8) | (src[1] & 0xff));
-
-               SSVAL(dst,ret,doscp_to_ucs2[val]);
-               ret += 2;
-               len -= 2;
-               if (skip)
-                       src += skip;
-               else
-                       src++;
-       }
-       SSVAL(dst,ret,0);
-       return(ret);
-}
+/* these 3 tables define the unicode case handling.  They are loaded
+   at startup either via mmap() or read() from the lib directory */
+static smb_ucs2_t *upcase_table;
+static smb_ucs2_t *lowcase_table;
+static uint8 *valid_table;
 
 /*******************************************************************
- Skip past some unicode strings in a buffer.
+load the case handling tables
 ********************************************************************/
-
-char *skip_unicode_string(char *buf,int n)
+void load_case_tables(void)
 {
-       while (n--) {
-               while (*buf)
-                       buf += 2;
-               buf += 2;
-       }
-       return(buf);
-}
+       static int initialised;
+       int i;
 
-/*******************************************************************
- Return a DOS codepage version of a little-endian unicode string.
- Hack alert: uses fixed buffer(s).
-********************************************************************/
+       if (initialised) return;
+       initialised = 1;
 
-char *dos_unistrn2(uint16 *src, int len)
-{
-       static char lbufs[8][MAXUNI];
-       static int nexti;
-       char *lbuf = lbufs[nexti];
-       char *p;
-
-       nexti = (nexti+1)%8;
+       upcase_table = map_file(lib_path("upcase.dat"), 0x20000);
+       lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000);
+       valid_table = map_file(lib_path("valid.dat"), 0x10000);
 
-       for (p = lbuf; (len > 0) && (p-lbuf < MAXUNI-3) && *src; len--, src++) {
-               uint16 ucs2_val = SVAL(src,0);
-               uint16 cp_val = ucs2_to_doscp[ucs2_val];
+       /* we would like Samba to limp along even if these tables are
+          not available */
+       if (!upcase_table) {
+               DEBUG(1,("creating lame upcase table\n"));
+               upcase_table = malloc(0x20000);
+               for (i=0;i<256;i++) upcase_table[i] = islower(i)?toupper(i):i;
+               for (;i<0x10000;i++) upcase_table[i] = i;
+       }
 
-               if (cp_val < 256)
-                       *p++ = (char)cp_val;
-               else {
-                       *p++ = (cp_val >> 8) & 0xff;
-                       *p++ = (cp_val & 0xff);
-               }
+       if (!lowcase_table) {
+               DEBUG(1,("creating lame lowcase table\n"));
+               lowcase_table = malloc(0x20000);
+               for (i=0;i<256;i++) lowcase_table[i] = isupper(i)?tolower(i):i;
+               for (;i<0x10000;i++) lowcase_table[i] = i;
        }
 
-       *p = 0;
-       return lbuf;
+       if (!valid_table) {
+               const char *allowed = "!#$%&'()_-.@^`{}~";
+               DEBUG(1,("creating lame valid table\n"));
+               valid_table = malloc(0x10000);
+               for (i=0;i<256;i++) valid_table[i] = isalnum(i) || strchr(allowed,i);
+               for (;i<0x10000;i++) valid_table[i] = 0;
+       }
 }
 
-static char lbufs[8][MAXUNI];
-static int nexti;
 
 /*******************************************************************
- Return a DOS codepage version of a little-endian unicode string.
- Hack alert: uses fixed buffer(s).
-********************************************************************/
-
-char *dos_unistr2(uint16 *src)
-{
-       char *lbuf = lbufs[nexti];
-       char *p;
-
-       nexti = (nexti+1)%8;
-
-       for (p = lbuf; *src && (p-lbuf < MAXUNI-3); src++) {
-               uint16 ucs2_val = SVAL(src,0);
-               uint16 cp_val = ucs2_to_doscp[ucs2_val];
+ Write a string in (little-endian) unicode format. src is in
+ the current DOS codepage. len is the length in bytes of the
+ string pointed to by dst.
 
-               if (cp_val < 256)
-                       *p++ = (char)cp_val;
-               else {
-                       *p++ = (cp_val >> 8) & 0xff;
-                       *p++ = (cp_val & 0xff);
-               }
-       }
+ if null_terminate is True then null terminate the packet (adds 2 bytes)
 
-       *p = 0;
-       return lbuf;
-}
-
-/*******************************************************************
-Return a DOS codepage version of a little-endian unicode string
+ the return value is the length in bytes consumed by the string, including the
+ null termination if applied
 ********************************************************************/
 
-char *dos_unistr2_to_str(UNISTR2 *str)
+size_t dos_PutUniCode(char *dst,const char *src, ssize_t len, BOOL null_terminate)
 {
-       char *lbuf = lbufs[nexti];
-       char *p;
-       uint16 *src = str->buffer;
-       int max_size = MIN(sizeof(str->buffer)-3, str->uni_str_len);
-
-       nexti = (nexti+1)%8;
-
-       for (p = lbuf; *src && p-lbuf < max_size; src++) {
-               uint16 ucs2_val = SVAL(src,0);
-               uint16 cp_val = ucs2_to_doscp[ucs2_val];
-
-               if (cp_val < 256)
-                       *p++ = (char)cp_val;
-               else {
-                       *p++ = (cp_val >> 8) & 0xff;
-                       *p++ = (cp_val & 0xff);
-               }
-       }
-
-       *p = 0;
-       return lbuf;
+       return push_ucs2(NULL, dst, src, len, 
+                        STR_UNICODE|STR_NOALIGN | (null_terminate?STR_TERMINATE:0));
 }
 
-/*******************************************************************
-Return a number stored in a buffer
-********************************************************************/
-
-uint32 buffer2_to_uint32(BUFFER2 *str)
-{
-       if (str->buf_len == 4)
-               return IVAL(str->buffer, 0);
-       else
-               return 0;
-}
 
 /*******************************************************************
-Return a DOS codepage version of a NOTunicode string
+ Skip past a unicode string, but not more than len. Always move
+ past a terminating zero if found.
 ********************************************************************/
 
-char *dos_buffer2_to_str(BUFFER2 *str)
+char *skip_unibuf(char *src, size_t len)
 {
-       char *lbuf = lbufs[nexti];
-       char *p;
-       uint16 *src = str->buffer;
-       int max_size = MIN(sizeof(str->buffer)-3, str->buf_len/2);
-
-       nexti = (nexti+1)%8;
+    char *srcend = src + len;
 
-       for (p = lbuf; *src && p-lbuf < max_size; src++) {
-               uint16 ucs2_val = SVAL(src,0);
-               uint16 cp_val = ucs2_to_doscp[ucs2_val];
+    while (src < srcend && SVAL(src,0))
+        src += 2;
 
-               if (cp_val < 256)
-                       *p++ = (char)cp_val;
-               else {
-                       *p++ = (cp_val >> 8) & 0xff;
-                       *p++ = (cp_val & 0xff);
-               }
-       }
+    if(!SVAL(src,0))
+        src += 2;
 
-       *p = 0;
-       return lbuf;
+    return src;
 }
 
-/*******************************************************************
- Return a dos codepage version of a NOTunicode string
-********************************************************************/
-
-char *dos_buffer2_to_multistr(BUFFER2 *str)
+/* Copy a string from little-endian or big-endian unicode source (depending
+ * on flags) to internal samba format destination
+ */ 
+int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
 {
-       char *lbuf = lbufs[nexti];
-       char *p;
-       uint16 *src = str->buffer;
-       int max_size = MIN(sizeof(str->buffer)-3, str->buf_len/2);
-
-       nexti = (nexti+1)%8;
-
-       for (p = lbuf; p-lbuf < max_size; src++) {
-               if (*src == 0) {
-                       *p++ = ' ';
-               } else {
-                       uint16 ucs2_val = SVAL(src,0);
-                       uint16 cp_val = ucs2_to_doscp[ucs2_val];
-
-                       if (cp_val < 256)
-                               *p++ = (char)cp_val;
-                       else {
-                               *p++ = (cp_val >> 8) & 0xff;
-                               *p++ = (cp_val & 0xff);
-                       }
-               }
-       }
-
-       *p = 0;
-       return lbuf;
+       if(dest_len==-1) dest_len=MAXUNI-3;
+       return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
 }
 
-/*******************************************************************
- Create a null-terminated unicode string from a null-terminated DOS
- codepage string.
- Return number of unicode chars copied, excluding the null character.
- Unicode strings created are in little-endian format.
-********************************************************************/
+/* Copy a string from a unistr2 source to internal samba format
+   destination.  Use this instead of direct calls to rpcstr_pull() to avoid
+   having to determine whether the source string is null terminated. */
 
-size_t dos_struni2(char *dst, const char *src, size_t max_len)
+int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
 {
-       size_t len = 0;
-
-       if (dst == NULL)
-               return 0;
-
-       if (src != NULL) {
-               for (; *src && len < max_len-2; len++, dst +=2) {
-                       size_t skip = skip_multibyte_char(*src);
-                       smb_ucs2_t val = (*src & 0xff);
-
-                       /*
-                        * If this is a multibyte character (and all DOS/Windows
-                        * codepages have at maximum 2 byte multibyte characters)
-                        * then work out the index value for the unicode conversion.
-                        */
-
-                       if (skip == 2)
-                               val = ((val << 8) | (src[1] & 0xff));
-
-                       SSVAL(dst,0,doscp_to_ucs2[val]);
-                       if (skip)
-                               src += skip;
-                       else
-                               src++;
-               }
-       }
-
-       SSVAL(dst,0,0);
+        return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
+                         src->uni_str_len * 2, 0);
+}
 
-       return len;
+/* Converts a string from internal samba format to unicode
+ */ 
+int rpcstr_push(void* dest, const char *src, int dest_len, int flags)
+{
+       return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
 }
 
 /*******************************************************************
  Return a DOS codepage version of a little-endian unicode string.
+ len is the filename length (ignoring any terminating zero) in uin16
+ units. Always null terminates.
  Hack alert: uses fixed buffer(s).
 ********************************************************************/
-
-char *dos_unistr(char *buf)
+char *dos_unistrn2(const uint16 *src, int len)
 {
+       static char lbufs[8][MAXUNI];
+       static int nexti;
        char *lbuf = lbufs[nexti];
-       uint16 *src = (uint16 *)buf;
-       char *p;
-
        nexti = (nexti+1)%8;
-
-       for (p = lbuf; *src && p-lbuf < MAXUNI-3; src++) {
-               uint16 ucs2_val = SVAL(src,0);
-               uint16 cp_val = ucs2_to_doscp[ucs2_val];
-
-               if (cp_val < 256)
-                       *p++ = (char)cp_val;
-               else {
-                       *p++ = (cp_val >> 8) & 0xff;
-                       *p++ = (cp_val & 0xff);
-               }
-       }
-
-       *p = 0;
+       pull_ucs2(NULL, lbuf, src, MAXUNI-3, len*2, STR_NOALIGN);
        return lbuf;
 }
 
 /*******************************************************************
- Strcpy for unicode strings.  returns length (in num of wide chars)
+ Convert a (little-endian) UNISTR2 structure to an ASCII string
 ********************************************************************/
-
-int unistrcpy(char *dst, char *src)
+void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
 {
-       int num_wchars = 0;
-       uint16 *wsrc = (uint16 *)src;
-       uint16 *wdst = (uint16 *)dst;
-
-       while (*wsrc) {
-               *wdst++ = *wsrc++;
-               num_wchars++;
+       if (str == NULL) {
+               *dest='\0';
+               return;
        }
-       *wdst = 0;
-
-       return num_wchars;
+       pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
 }
 
 
-
 /*******************************************************************
- Free any existing maps.
+Return a number stored in a buffer
 ********************************************************************/
 
-static void free_maps(smb_ucs2_t **pp_cp_to_ucs2, uint16 **pp_ucs2_to_cp)
+uint32 buffer2_to_uint32(BUFFER2 *str)
 {
-       /* this handles identity mappings where we share the pointer */
-       if (*pp_ucs2_to_cp == *pp_cp_to_ucs2) {
-               *pp_ucs2_to_cp = NULL;
-       }
-
-       if (*pp_cp_to_ucs2) {
-               free(*pp_cp_to_ucs2);
-               *pp_cp_to_ucs2 = NULL;
-       }
-
-       if (*pp_ucs2_to_cp) {
-               free(*pp_ucs2_to_cp);
-               *pp_ucs2_to_cp = NULL;
-       }
+       if (str->buf_len == 4)
+               return IVAL(str->buffer, 0);
+       else
+               return 0;
 }
 
-
 /*******************************************************************
Build a default (null) codepage to unicode map.
Convert a wchar to upper case.
 ********************************************************************/
 
-void default_unicode_map(smb_ucs2_t **pp_cp_to_ucs2, uint16 **pp_ucs2_to_cp)
+smb_ucs2_t toupper_w(smb_ucs2_t val)
 {
-  int i;
-
-  free_maps(pp_cp_to_ucs2, pp_ucs2_to_cp);
-
-  if ((*pp_ucs2_to_cp = (uint16 *)malloc(2*65536)) == NULL) {
-    DEBUG(0,("default_unicode_map: malloc fail for ucs2_to_cp size %u.\n", 2*65536));
-    abort();
-  }
-
-  *pp_cp_to_ucs2 = *pp_ucs2_to_cp; /* Default map is an identity. */
-  for (i = 0; i < 65536; i++)
-    (*pp_cp_to_ucs2)[i] = i;
+       return upcase_table[SVAL(&val,0)];
 }
 
 /*******************************************************************
Load a codepage to unicode and vica-versa map.
Convert a wchar to lower case.
 ********************************************************************/
 
-BOOL load_unicode_map(const char *codepage, smb_ucs2_t **pp_cp_to_ucs2, uint16 **pp_ucs2_to_cp)
+smb_ucs2_t tolower_w( smb_ucs2_t val )
 {
-  pstring unicode_map_file_name;
-  FILE *fp = NULL;
-  SMB_STRUCT_STAT st;
-  smb_ucs2_t *cp_to_ucs2 = *pp_cp_to_ucs2;
-  uint16 *ucs2_to_cp = *pp_ucs2_to_cp;
-  size_t cp_to_ucs2_size;
-  size_t ucs2_to_cp_size;
-  size_t i;
-  size_t size;
-  char buf[UNICODE_MAP_HEADER_SIZE];
-
-  DEBUG(5, ("load_unicode_map: loading unicode map for codepage %s.\n", codepage));
-
-  if (*codepage == '\0')
-    goto clean_and_exit;
-
-  if(strlen(CODEPAGEDIR) + 13 + strlen(codepage) > sizeof(unicode_map_file_name)) {
-    DEBUG(0,("load_unicode_map: filename too long to load\n"));
-    goto clean_and_exit;
-  }
-
-  pstrcpy(unicode_map_file_name, CODEPAGEDIR);
-  pstrcat(unicode_map_file_name, "/");
-  pstrcat(unicode_map_file_name, "unicode_map.");
-  pstrcat(unicode_map_file_name, codepage);
-
-  if(sys_stat(unicode_map_file_name,&st)!=0) {
-    DEBUG(0,("load_unicode_map: filename %s does not exist.\n",
-              unicode_map_file_name));
-    goto clean_and_exit;
-  }
-
-  size = st.st_size;
-
-  if ((size != UNICODE_MAP_HEADER_SIZE + 4*65536) && (size != UNICODE_MAP_HEADER_SIZE +(2*256 + 2*65536))) {
-    DEBUG(0,("load_unicode_map: file %s is an incorrect size for a \
-unicode map file (size=%d).\n", unicode_map_file_name, (int)size));
-    goto clean_and_exit;
-  }
-
-  if((fp = sys_fopen( unicode_map_file_name, "r")) == NULL) {
-    DEBUG(0,("load_unicode_map: cannot open file %s. Error was %s\n",
-              unicode_map_file_name, strerror(errno)));
-    goto clean_and_exit;
-  }
-
-  if(fread( buf, 1, UNICODE_MAP_HEADER_SIZE, fp)!=UNICODE_MAP_HEADER_SIZE) {
-    DEBUG(0,("load_unicode_map: cannot read header from file %s. Error was %s\n",
-              unicode_map_file_name, strerror(errno)));
-    goto clean_and_exit;
-  }
-
-  /* Check the version value */
-  if(SVAL(buf,UNICODE_MAP_VERSION_OFFSET) != UNICODE_MAP_FILE_VERSION_ID) {
-    DEBUG(0,("load_unicode_map: filename %s has incorrect version id. \
-Needed %hu, got %hu.\n",
-          unicode_map_file_name, (uint16)UNICODE_MAP_FILE_VERSION_ID,
-          SVAL(buf,UNICODE_MAP_VERSION_OFFSET)));
-    goto clean_and_exit;
-  }
-
-  /* Check the codepage value */
-  if(!strequal(&buf[UNICODE_MAP_CLIENT_CODEPAGE_OFFSET], codepage)) {
-    DEBUG(0,("load_unicode_map: codepage %s in file %s is not the same as that \
-requested (%s).\n", &buf[UNICODE_MAP_CLIENT_CODEPAGE_OFFSET], unicode_map_file_name, codepage ));
-    goto clean_and_exit;
-  }
-
-  ucs2_to_cp_size = 2*65536;
-  if (size == UNICODE_MAP_HEADER_SIZE + 4*65536) {
-    /* 
-     * This is a multibyte code page.
-     */
-    cp_to_ucs2_size = 2*65536;
-  } else {
-    /*
-     * Single byte code page.
-     */
-    cp_to_ucs2_size = 2*256;
-  }
-
-  /* 
-   * Free any old translation tables.
-   */
-
-  free_maps(pp_cp_to_ucs2, pp_ucs2_to_cp);
-
-  if ((cp_to_ucs2 = (smb_ucs2_t *)malloc(cp_to_ucs2_size)) == NULL) {
-    DEBUG(0,("load_unicode_map: malloc fail for cp_to_ucs2 size %u.\n", cp_to_ucs2_size ));
-    goto clean_and_exit;
-  }
-
-  if ((ucs2_to_cp = (uint16 *)malloc(ucs2_to_cp_size)) == NULL) {
-    DEBUG(0,("load_unicode_map: malloc fail for ucs2_to_cp size %u.\n", ucs2_to_cp_size ));
-    goto clean_and_exit;
-  }
-
-  if(fread( (char *)cp_to_ucs2, 1, cp_to_ucs2_size, fp)!=cp_to_ucs2_size) {
-    DEBUG(0,("load_unicode_map: cannot read cp_to_ucs2 from file %s. Error was %s\n",
-              unicode_map_file_name, strerror(errno)));
-    goto clean_and_exit;
-  }
-
-  if(fread( (char *)ucs2_to_cp, 1, ucs2_to_cp_size, fp)!=ucs2_to_cp_size) {
-    DEBUG(0,("load_unicode_map: cannot read ucs2_to_cp from file %s. Error was %s\n",
-              unicode_map_file_name, strerror(errno)));
-    goto clean_and_exit;
-  }
-
-  /*
-   * Now ensure the 16 bit values are in the correct endianness.
-   */
-
-  for (i = 0; i < cp_to_ucs2_size/2; i++)
-    cp_to_ucs2[i] = SVAL(cp_to_ucs2,i*2);
-
-  for (i = 0; i < ucs2_to_cp_size/2; i++)
-    ucs2_to_cp[i] = SVAL(ucs2_to_cp,i*2);
-
-  fclose(fp);
-
-  *pp_cp_to_ucs2 = cp_to_ucs2;
-  *pp_ucs2_to_cp = ucs2_to_cp;
-
-  return True;
-
-clean_and_exit:
-
-  /* pseudo destructor :-) */
-
-  if(fp != NULL)
-    fclose(fp);
-
-  free_maps(pp_cp_to_ucs2, pp_ucs2_to_cp);
-
-  default_unicode_map(pp_cp_to_ucs2, pp_ucs2_to_cp);
-
-  return False;
+       return lowcase_table[SVAL(&val,0)];
 }
 
 /*******************************************************************
- Load a dos codepage to unicode and vica-versa map.
+determine if a character is lowercase
 ********************************************************************/
-
-BOOL load_dos_unicode_map(int codepage)
+BOOL islower_w(smb_ucs2_t c)
 {
-  fstring codepage_str;
-
-  slprintf(codepage_str, sizeof(fstring)-1, "%03d", codepage);
-  return load_unicode_map(codepage_str, &doscp_to_ucs2, &ucs2_to_doscp);
+       return upcase_table[SVAL(&c,0)] != c;
 }
 
 /*******************************************************************
- Load a UNIX codepage to unicode and vica-versa map.
+determine if a character is uppercase
 ********************************************************************/
-
-BOOL load_unix_unicode_map(const char *unix_char_set)
+BOOL isupper_w(smb_ucs2_t c)
 {
-  fstring upper_unix_char_set;
-
-  fstrcpy(upper_unix_char_set, unix_char_set);
-  strupper(upper_unix_char_set);
-  return load_unicode_map(upper_unix_char_set, &unixcp_to_ucs2, &ucs2_to_unixcp);
+       return lowcase_table[SVAL(&c,0)] != c;
 }
 
-/*******************************************************************
- The following functions reproduce many of the non-UNICODE standard
- string functions in Samba.
-********************************************************************/
 
 /*******************************************************************
- Convert a UNICODE string to multibyte format. Note that the 'src' is in
- native byte order, not little endian. Always zero terminates.
- dst_len is in bytes.
+determine if a character is valid in a 8.3 name
 ********************************************************************/
-
-static char *unicode_to_multibyte(char *dst, const smb_ucs2_t *src,
-                                  size_t dst_len, const uint16 *ucs2_to_cp)
+BOOL isvalid83_w(smb_ucs2_t c)
 {
-       size_t dst_pos;
-
-       for(dst_pos = 0; *src && (dst_pos < dst_len - 1);) {
-               smb_ucs2_t val = ucs2_to_cp[*src++];
-               if(val < 256) {
-                       dst[dst_pos++] = (char)val;
-               } else {
-
-                       if(dst_pos >= dst_len - 2)
-                               break;
-
-                       /*
-                        * A 2 byte value is always written as
-                        * high/low into the buffer stream.
-                        */
-
-                       dst[dst_pos++] = (char)((val >> 8) & 0xff);
-                       dst[dst_pos++] = (char)(val & 0xff);
-               }
-       }       
-
-       dst[dst_pos] = '\0';
-
-       return dst;
+       return valid_table[SVAL(&c,0)] != 0;
 }
 
 /*******************************************************************
- Convert a multibyte string to UNICODE format. Note that the 'dst' is in
- native byte order, not little endian. Always zero terminates.
- dst_len is in bytes.
+ Count the number of characters in a smb_ucs2_t string.
 ********************************************************************/
-
-smb_ucs2_t *multibyte_to_unicode(smb_ucs2_t *dst, const char *src,
-                                 size_t dst_len, smb_ucs2_t *cp_to_ucs2)
+size_t strlen_w(const smb_ucs2_t *src)
 {
-       size_t i;
+       size_t len;
 
-       dst_len /= sizeof(smb_ucs2_t); /* Convert to smb_ucs2_t units. */
+       for(len = 0; *src++; len++) ;
 
-       for(i = 0; (i < (dst_len  - 1)) && src[i];) {
-               size_t skip = skip_multibyte_char(*src);
-               smb_ucs2_t val = (*src & 0xff);
-
-               /*
-                * If this is a multibyte character
-                * then work out the index value for the unicode conversion.
-                */
-
-               if (skip == 2)
-                       val = ((val << 8) | (src[1] & 0xff));
-
-               dst[i++] = cp_to_ucs2[val];
-               if (skip)
-                       src += skip;
-               else
-                       src++;
-       }
-
-       dst[i] = 0;
-
-       return dst;
+       return len;
 }
 
 /*******************************************************************
- Convert a UNICODE string to multibyte format. Note that the 'src' is in
- native byte order, not little endian. Always zero terminates.
- This function may be replaced if the MB  codepage format is an
- encoded one (ie. utf8, hex). See the code in lib/kanji.c
- for details. dst_len is in bytes.
+wide strchr()
 ********************************************************************/
-
-char *unicode_to_unix(char *dst, const smb_ucs2_t *src, size_t dst_len)
+smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
 {
-       return unicode_to_multibyte(dst, src, dst_len, ucs2_to_unixcp);
+       while (*s != 0) {
+               if (c == *s) return (smb_ucs2_t *)s;
+               s++;
+       }
+       return NULL;
 }
 
+
 /*******************************************************************
- Convert a UNIX string to UNICODE format. Note that the 'dst' is in
- native byte order, not little endian. Always zero terminates.
- This function may be replaced if the UNIX codepage format is a
- multi-byte one (ie. JIS, SJIS or utf8). See the code in lib/kanji.c
- for details. dst_len is in bytes, not ucs2 units.
+ Convert a string to lower case.
+ return True if any char is converted
 ********************************************************************/
-
-smb_ucs2_t *unix_to_unicode(smb_ucs2_t *dst, const char *src, size_t dst_len)
+BOOL strlower_w(smb_ucs2_t *s)
 {
-       return multibyte_to_unicode(dst, src, dst_len, unixcp_to_ucs2);
+       BOOL ret = False;
+       while (*s) {
+               smb_ucs2_t v = tolower_w(*s);
+               if (v != *s) {
+                       *s = v;
+                       ret = True;
+               }
+               s++;
+       }
+       return ret;
 }
 
 /*******************************************************************
- Convert a UNICODE string to DOS format. Note that the 'src' is in
- native byte order, not little endian. Always zero terminates. 
- dst_len is in bytes.
-********************************************************************/ 
-
-char *unicode_to_dos(char *dst, const smb_ucs2_t *src, size_t dst_len)
+ Convert a string to upper case.
+ return True if any char is converted
+********************************************************************/
+BOOL strupper_w(smb_ucs2_t *s)
 {
-       return unicode_to_multibyte(dst, src, dst_len, ucs2_to_doscp);
+       BOOL ret = False;
+       while (*s) {
+               smb_ucs2_t v = toupper_w(*s);
+               if (v != *s) {
+                       *s = v;
+                       ret = True;
+               }
+               s++;
+       }
+       return ret;
 }
 
 /*******************************************************************
- Convert a DOS string to UNICODE format. Note that the 'dst' is in
- native byte order, not little endian. Always zero terminates.
- This function may be replaced if the DOS codepage format is a
- multi-byte one (ie. JIS, SJIS or utf8). See the code in lib/kanji.c
- for details. dst_len is in bytes, not ucs2 units.
+case insensitive string comparison
 ********************************************************************/
-
-smb_ucs2_t *dos_to_unicode(smb_ucs2_t *dst, const char *src, size_t dst_len)
+int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
 {
-       return multibyte_to_unicode(dst, src, dst_len, doscp_to_ucs2);
+       while (*b && toupper_w(*a) == toupper_w(*b)) { a++; b++; }
+       return (tolower_w(*a) - tolower_w(*b));
 }
 
+
 /*******************************************************************
- Count the number of characters in a smb_ucs2_t string.
+duplicate string
 ********************************************************************/
-
-size_t wstrlen(const smb_ucs2_t *src)
+smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
 {
-  size_t len;
-
-  for(len = 0; *src; len++)
-    ;
+       smb_ucs2_t *dest;
+       uint32 len;
+       
+       len = strlen_w(src) + 1;
+       dest = (smb_ucs2_t *)malloc(len*sizeof(smb_ucs2_t));
+       if (!dest) {
+               DEBUG(0,("strdup_w: out of memory!\n"));
+               return NULL;
+       }
 
-  return len;
+       memcpy(dest, src, len*sizeof(smb_ucs2_t));
+       
+       return dest;
 }
 
 /*******************************************************************
- Safe wstring copy into a known length string. maxlength includes
- the terminating zero. maxlength is in bytes.
+copy a string with max len
 ********************************************************************/
 
-smb_ucs2_t *safe_wstrcpy(smb_ucs2_t *dest,const smb_ucs2_t *src, size_t maxlength)
+smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
 {
-    size_t ucs2_len;
-
-    if (!dest) {
-        DEBUG(0,("ERROR: NULL dest in safe_wstrcpy\n"));
-        return NULL;
-    }
-
-    if (!src) {
-        *dest = 0;
-        return dest;
-    }
-
-       ucs2_len = wstrlen(src);
-
-    if (ucs2_len >= (maxlength/sizeof(smb_ucs2_t))) {
-               fstring out;
-        DEBUG(0,("ERROR: string overflow by %u bytes in safe_wstrcpy [%.50s]\n",
-                       (unsigned int)((ucs2_len*sizeof(smb_ucs2_t))-maxlength),
-                       unicode_to_unix(out,src,sizeof(out))) );
-               ucs2_len = (maxlength/sizeof(smb_ucs2_t)) - 1;
-    }
-
-    memcpy(dest, src, ucs2_len*sizeof(smb_ucs2_t));
-    dest[ucs2_len] = 0;
-    return dest;
+       size_t len;
+       
+       if (!dest || !src) return NULL;
+       
+       for (len = 0; (src[len] != 0) && (len < max); len++)
+               dest[len] = src[len];
+       while (len < max)
+               dest[len++] = 0;
+       
+       return dest;
 }
 
-/*******************************************************************
- Safe string cat into a string. maxlength includes the terminating zero.
- maxlength is in bytes.
-********************************************************************/
-
-smb_ucs2_t *safe_wstrcat(smb_ucs2_t *dest, const smb_ucs2_t *src, size_t maxlength)
-{
-    size_t ucs2_src_len, ucs2_dest_len;
-
-    if (!dest) {
-        DEBUG(0,("ERROR: NULL dest in safe_wstrcat\n"));
-        return NULL;
-    }
-
-    if (!src) {
-        return dest;
-    }
-
-    ucs2_src_len = wstrlen(src);
-    ucs2_dest_len = wstrlen(dest);
-
-    if (ucs2_src_len + ucs2_dest_len >= (maxlength/sizeof(smb_ucs2_t))) {
-               fstring out;
-               int new_len = (maxlength/sizeof(smb_ucs2_t)) - ucs2_dest_len - 1;
-        DEBUG(0,("ERROR: string overflow by %u characters in safe_wstrcat [%.50s]\n",
-                       (unsigned int)((sizeof(smb_ucs2_t)*(ucs2_src_len + ucs2_dest_len)) - maxlength),
-                       unicode_to_unix(out,src,sizeof(out))) );
-        ucs2_src_len = (size_t)(new_len > 0 ? new_len : 0);
-    }
-
-    memcpy(&dest[ucs2_dest_len], src, ucs2_src_len*sizeof(smb_ucs2_t));
-    dest[ucs2_dest_len + ucs2_src_len] = 0;
-    return dest;
-}
 
 /*******************************************************************
- Compare the two strings s1 and s2. len is in ucs2 units.
+append a string of len bytes and add a terminator
 ********************************************************************/
 
-int wstrcmp(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
-{
-       smb_ucs2_t c1, c2;
-
-       for (;;) {
-               c1 = *s1++;
-               c2 = *s2++;
+smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
+{      
+       size_t start;
+       size_t len;     
+       
+       if (!dest || !src) return NULL;
+       
+       start = strlen_w(dest);
+       len = strlen_w(src);
+       if (len > max) len = max;
 
-               if (c1 != c2)
-                       return c1 - c2;
-
-               if (c1 == 0)
-            return 0;
-    }
-       return 0;
+       memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));                      
+       dest[start+len] = 0;
+       
+       return dest;
 }
 
-/*******************************************************************
- Compare the first n characters of s1 to s2. len is in ucs2 units.
-********************************************************************/
 
-int wstrncmp(const smb_ucs2_t *s1, const smb_ucs2_t *s2, size_t len)
-{
-       smb_ucs2_t c1, c2;
-
-       for (; len != 0; --len) {
-               c1 = *s1++;
-               c2 = *s2++;
-
-               if (c1 != c2)
-                       return c1 - c2;
+/*
+  The *_wa() functions take a combination of 7 bit ascii
+  and wide characters They are used so that you can use string
+  functions combining C string constants with ucs2 strings
 
-               if (c1 == 0)
-                       return 0;
+  The char* arguments must NOT be multibyte - to be completely sure
+  of this only pass string constants */
 
-    }
-       return 0;
-}
-
-/*******************************************************************
- Search string s2 from s1.
-********************************************************************/
 
-smb_ucs2_t *wstrstr(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
+void pstrcpy_wa(smb_ucs2_t *dest, const char *src)
 {
-       size_t len = wstrlen(s2);
-
-       if (!*s2)
-               return (smb_ucs2_t *)s1;
-
-       for(;*s1; s1++) {
-               if (*s1 == *s2) {
-                       if (wstrncmp(s1, s2, len) == 0)
-                               return (smb_ucs2_t *)s1;
-               }
+       int i;
+       for (i=0;i<PSTRING_LEN;i++) {
+               dest[i] = UCS2_CHAR(src[i]);
+               if (src[i] == 0) return;
        }
-       return NULL; 
 }
 
-/*******************************************************************
- Search for ucs2 char c from the beginning of s.
-********************************************************************/ 
-
-smb_ucs2_t *wstrchr(const smb_ucs2_t *s, smb_ucs2_t c)
+int strcmp_wa(const smb_ucs2_t *a, const char *b)
 {
-       do {
-               if (*s == c)
-                       return (smb_ucs2_t *)s;
-       } while (*s++);
-
-       return NULL;
+       while (*b && *a == UCS2_CHAR(*b)) { a++; b++; }
+       return (*a - UCS2_CHAR(*b));
 }
 
-/*******************************************************************
- Search for ucs2 char c from the end of s.
-********************************************************************/ 
-
-smb_ucs2_t *wstrrchr(const smb_ucs2_t *s, smb_ucs2_t c)
-{
-       smb_ucs2_t *retval = 0;
-
-       do {
-               if (*s == c)
-                       retval = (smb_ucs2_t *)s;
-       } while (*s++);
 
-       return retval;
-}
 
-/*******************************************************************
- Search token from s1 separated by any ucs2 char of s2.
-********************************************************************/
-
-smb_ucs2_t *wstrtok(smb_ucs2_t *s1, const smb_ucs2_t *s2)
+smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
 {
-       static smb_ucs2_t *s = NULL;
-       smb_ucs2_t *q;
-
-       if (!s1) {
-               if (!s)
-                       return NULL;
-               s1 = s;
-       }
-
-       for (q = s1; *s1; s1++) {
-               smb_ucs2_t *p = wstrchr(s2, *s1);
-               if (p) {
-                       if (s1 != q) {
-                               s = s1 + 1;
-                               *s1 = '\0';
-                               return q;
-                       }
-                       q = s1 + 1;
-               }
+       while (*s != 0) {
+               if (UCS2_CHAR(c) == *s) return (smb_ucs2_t *)s;
+               s++;
        }
-
-       s = NULL;
-       if (*q)
-               return q;
-
        return NULL;
 }
 
-/*******************************************************************
- Duplicate a ucs2 string.
-********************************************************************/
-
-smb_ucs2_t *wstrdup(const smb_ucs2_t *s)
+smb_ucs2_t *strrchr_wa(const smb_ucs2_t *s, char c)
 {
-       size_t newlen = (wstrlen(s)+1)*sizeof(smb_ucs2_t);
-       smb_ucs2_t *newstr = (smb_ucs2_t *)malloc(newlen);
-    if (newstr == NULL)
-        return NULL;
-    safe_wstrcpy(newstr, s, newlen);
-    return newstr;
+       const smb_ucs2_t *p = s;
+       int len = strlen_w(s);
+       if (len == 0) return NULL;
+       p += (len-1);
+       do {
+               if (UCS2_CHAR(c) == *p) return (smb_ucs2_t *)p;
+       } while (p-- != s);
+       return NULL;
 }
 
-/*******************************************************************
- Mapping tables for UNICODE character. Allows toupper/tolower and
- isXXX functions to work.
-********************************************************************/
-
-typedef struct {
-       smb_ucs2_t lower;
-       smb_ucs2_t upper;
-       unsigned char flags;
-} smb_unicode_table_t;
-
-static smb_unicode_table_t map_table[] = {
-#include "unicode_map_table.h"
-};
-
-/*******************************************************************
- Is an upper case wchar.
-********************************************************************/
-
-int wisupper( smb_ucs2_t val)
+smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
 {
-       return (map_table[val].flags & UNI_UPPER);
+       while (*s != 0) {
+               int i;
+               for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++) 
+                       ;
+               if (p[i]) return (smb_ucs2_t *)s;
+               s++;
+       }
+       return NULL;
 }
 
-/*******************************************************************
- Is a lower case wchar.
-********************************************************************/
-
-int wislower( smb_ucs2_t val)
-{
-       return (map_table[val].flags & UNI_LOWER);
-}
 
 /*******************************************************************
- Is a digit wchar.
+copy a string with max len
 ********************************************************************/
 
-int wisdigit( smb_ucs2_t val)
+smb_ucs2_t *strncpy_wa(smb_ucs2_t *dest, const char *src, const size_t max)
 {
-       return (map_table[val].flags & UNI_DIGIT);
-}
-
-/*******************************************************************
- Is a hex digit wchar.
-********************************************************************/
+       smb_ucs2_t *ucs2_src;
 
-int wisxdigit( smb_ucs2_t val)
-{
-       return (map_table[val].flags & UNI_XDIGIT);
+       if (!dest || !src) return NULL;
+       ucs2_src = (smb_ucs2_t *)malloc((strlen(src)+1)*sizeof(smb_ucs2_t));
+       if (!ucs2_src) {
+               DEBUG(0,("strncpy_wa: out of memory!\n"));
+               return NULL;
+       }
+       push_ucs2(NULL, ucs2_src, src, -1, STR_TERMINATE|STR_NOALIGN);
+       
+       strncpy_w(dest, ucs2_src, max);
+       SAFE_FREE(ucs2_src);
+       return dest;
 }
 
-/*******************************************************************
- Is a space wchar.
-********************************************************************/
-
-int wisspace( smb_ucs2_t val)
-{
-       return (map_table[val].flags & UNI_SPACE);
-}
 
 /*******************************************************************
- Convert a wchar to upper case.
+append a string of len bytes and add a terminator
 ********************************************************************/
 
-smb_ucs2_t wtoupper( smb_ucs2_t val )
+smb_ucs2_t *strncat_wa(smb_ucs2_t *dest, const char *src, const size_t max)
 {
-       return map_table[val].upper;
-}
+       smb_ucs2_t *ucs2_src;
 
-/*******************************************************************
- Convert a wchar to lower case.
-********************************************************************/
-
-smb_ucs2_t wtolowerr( smb_ucs2_t val )
-{
-       return map_table[val].lower;
+       if (!dest || !src) return NULL;
+       ucs2_src = (smb_ucs2_t *)malloc((strlen(src)+1)*sizeof(smb_ucs2_t));
+       if (!ucs2_src) {
+               DEBUG(0,("strncat_wa: out of memory!\n"));
+               return NULL;
+       }
+       push_ucs2(NULL, ucs2_src, src, -1, STR_TERMINATE|STR_NOALIGN);
+       
+       strncat_w(dest, ucs2_src, max);
+       SAFE_FREE(ucs2_src);
+       return dest;
 }