r4267: fixed the charset code to use the builtin_functions.
[samba.git] / source4 / lib / iconv.c
index 9f6526faa5e35e5c8211ccab06934e3245aa88a9..181834d66aaeddb6c7f77bdbc1a0ea69db0ea057 100644 (file)
@@ -20,6 +20,8 @@
 */
 
 #include "includes.h"
+#include "dlinklist.h"
+#include "system/iconv.h"
 
 
 /**
@@ -54,7 +56,7 @@ static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *);
 static size_t iconv_copy  (void *,const char **, size_t *, char **, size_t *);
 static size_t iconv_swab  (void *,const char **, size_t *, char **, size_t *);
 
-static const struct charset_functions const builtin_functions[] = {
+static const struct charset_functions builtin_functions[] = {
        /* windows is closest to UTF-16 */
        {"UCS-2LE",  iconv_copy, iconv_copy},
        {"UTF-16LE",  iconv_copy, iconv_copy},
@@ -65,13 +67,12 @@ static const struct charset_functions const builtin_functions[] = {
        {"UTF8",   utf8_pull,  utf8_push},
        {"UTF-8",   utf8_pull,  utf8_push},
        {"ASCII", ascii_pull, ascii_push},
-       {"UCS2-HEX", ucs2hex_pull, ucs2hex_push},
-       {NULL, NULL, NULL}
+       {"UCS2-HEX", ucs2hex_pull, ucs2hex_push}
 };
 
 static struct charset_functions *charsets = NULL;
 
-static NTSTATUS charset_register_backend(const void *_funcs) 
+NTSTATUS charset_register_backend(const void *_funcs) 
 {
        struct charset_functions *funcs = memdup(_funcs,sizeof(struct charset_functions));
        struct charset_functions *c = charsets;
@@ -90,20 +91,6 @@ static NTSTATUS charset_register_backend(const void *_funcs)
        return NT_STATUS_OK;
 }
 
-static void lazy_initialize_iconv(void)
-{
-       static BOOL initialized = False;
-       int i;
-
-       if (!initialized) {
-               initialized = True;
-               register_subsystem("charset", charset_register_backend);
-               
-               for(i = 0; builtin_functions[i].name; i++) 
-                       register_backend("charset", &builtin_functions[i]);
-       }
-}
-
 #ifdef HAVE_NATIVE_ICONV
 /* if there was an error then reset the internal state,
    this ensures that we don't have a shift state remaining for
@@ -113,7 +100,7 @@ static size_t sys_iconv(void *cd,
                        char **outbuf, size_t *outbytesleft)
 {
        size_t ret = iconv((iconv_t)cd, 
-                          inbuf, inbytesleft, 
+                          discard_const_p(char *, inbuf), inbytesleft, 
                           outbuf, outbytesleft);
        if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
        return ret;
@@ -131,7 +118,6 @@ size_t smb_iconv(smb_iconv_t cd,
                 char **outbuf, size_t *outbytesleft)
 {
        char cvtbuf[2048];
-       char *bufp = cvtbuf;
        size_t bufsize;
 
        /* in many cases we can go direct */
@@ -143,72 +129,89 @@ size_t smb_iconv(smb_iconv_t cd,
 
        /* otherwise we have to do it chunks at a time */
        while (*inbytesleft > 0) {
-               bufp = cvtbuf;
+               char *bufp1 = cvtbuf;
+               const char *bufp2 = cvtbuf;
+
                bufsize = sizeof(cvtbuf);
                
                if (cd->pull(cd->cd_pull, 
-                            inbuf, inbytesleft, &bufp, &bufsize) == -1
+                            inbuf, inbytesleft, &bufp1, &bufsize) == -1
                    && errno != E2BIG) return -1;
 
-               bufp = cvtbuf;
                bufsize = sizeof(cvtbuf) - bufsize;
 
                if (cd->push(cd->cd_push, 
-                            &bufp, &bufsize, 
+                            &bufp2, &bufsize, 
                             outbuf, outbytesleft) == -1) return -1;
        }
 
        return 0;
 }
 
+static BOOL is_utf16(const char *name)
+{
+       return strcasecmp(name, "UCS-2LE") == 0 ||
+               strcasecmp(name, "UTF-16LE") == 0;
+}
+
 /*
   simple iconv_open() wrapper
  */
 smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
 {
        smb_iconv_t ret;
-       struct charset_functions *from, *to;
-       
-       lazy_initialize_iconv();
-       from = charsets;
-       to = charsets;
+       const struct charset_functions *from=NULL, *to=NULL;
+       int i;
 
-       ret = (smb_iconv_t)malloc(sizeof(*ret));
+       ret = (smb_iconv_t)talloc_named(NULL, sizeof(*ret), 
+                                       "iconv(%s,%s)", tocode, fromcode);
        if (!ret) {
                errno = ENOMEM;
                return (smb_iconv_t)-1;
        }
        memset(ret, 0, sizeof(*ret));
 
-       ret->from_name = strdup(fromcode);
-       ret->to_name = strdup(tocode);
-
        /* check for the simplest null conversion */
        if (strcmp(fromcode, tocode) == 0) {
                ret->direct = iconv_copy;
                return ret;
        }
 
-       while (from) {
-               if (strcasecmp(from->name, fromcode) == 0) break;
-               from = from->next;
+       for (i=0;i<ARRAY_SIZE(builtin_functions);i++) {
+               if (strcasecmp(fromcode, builtin_functions[i].name) == 0) {
+                       from = &builtin_functions[i];
+               }
+               if (strcasecmp(tocode, builtin_functions[i].name) == 0) {
+                       to = &builtin_functions[i];
+               }
        }
 
-       while (to) {
-               if (strcasecmp(to->name, tocode) == 0) break;
-               to = to->next;
+       if (from == NULL) {
+               for (from=charsets; from; from=from->next) {
+                       if (strcasecmp(from->name, fromcode) == 0) break;
+               }
+       }
+
+       if (to == NULL) {
+               for (to=charsets; to; to=to->next) {
+                       if (strcasecmp(to->name, tocode) == 0) break;
+               }
        }
 
 #ifdef HAVE_NATIVE_ICONV
        if (!from) {
                ret->pull = sys_iconv;
-               ret->cd_pull = iconv_open("UCS-2LE", fromcode);
+               ret->cd_pull = iconv_open("UTF-16LE", fromcode);
+               if (ret->cd_pull == (iconv_t)-1)
+                       ret->cd_pull = iconv_open("UCS-2LE", fromcode);
                if (ret->cd_pull == (iconv_t)-1) goto failed;
        }
 
        if (!to) {
                ret->push = sys_iconv;
-               ret->cd_push = iconv_open(tocode, "UCS-2LE");
+               ret->cd_push = iconv_open(tocode, "UTF-16LE");
+               if (ret->cd_push == (iconv_t)-1)
+                       ret->cd_push = iconv_open(tocode, "UCS-2LE");
                if (ret->cd_push == (iconv_t)-1) goto failed;
        }
 #else
@@ -218,23 +221,23 @@ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
 #endif
 
        /* check for conversion to/from ucs2 */
-       if (strcasecmp(fromcode, "UTF-16LE") == 0 && to) {
+       if (is_utf16(fromcode) && to) {
                ret->direct = to->push;
                return ret;
        }
-       if (strcasecmp(tocode, "UTF-16LE") == 0 && from) {
+       if (is_utf16(tocode) && from) {
                ret->direct = from->pull;
                return ret;
        }
 
 #ifdef HAVE_NATIVE_ICONV
-       if (strcasecmp(fromcode, "UTF-16LE") == 0) {
+       if (is_utf16(fromcode)) {
                ret->direct = sys_iconv;
                ret->cd_direct = ret->cd_push;
                ret->cd_push = NULL;
                return ret;
        }
-       if (strcasecmp(tocode, "UTF-16LE") == 0) {
+       if (is_utf16(tocode)) {
                ret->direct = sys_iconv;
                ret->cd_direct = ret->cd_pull;
                ret->cd_pull = NULL;
@@ -248,7 +251,7 @@ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
        return ret;
 
 failed:
-       SAFE_FREE(ret);
+       talloc_free(ret);
        errno = EINVAL;
        return (smb_iconv_t)-1;
 }
@@ -256,7 +259,7 @@ failed:
 /*
   simple iconv_close() wrapper
 */
-int smb_iconv_close (smb_iconv_t cd)
+int smb_iconv_close(smb_iconv_t cd)
 {
 #ifdef HAVE_NATIVE_ICONV
        if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
@@ -264,11 +267,7 @@ int smb_iconv_close (smb_iconv_t cd)
        if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
 #endif
 
-       SAFE_FREE(cd->from_name);
-       SAFE_FREE(cd->to_name);
-
-       memset(cd, 0, sizeof(*cd));
-       SAFE_FREE(cd);
+       talloc_free(cd);
        return 0;
 }
 
@@ -689,3 +688,5 @@ error:
        return -1;
 }
 
+
+