s3:dbwrap_ctdb: change db_ctdb_transaction_store() to return NTSTATUS.
[amitay/samba.git] / source3 / lib / charcnv.c
index 567ee7b8d160fa1755f8cd09dd22caaa58e54de0..9ac9930267ef6614738f0f5d75a933d3d8d958b9 100644 (file)
@@ -54,14 +54,30 @@ static bool initialized;
  **/
 static const char *charset_name(charset_t ch)
 {
-       const char *ret = NULL;
-
-       if (ch == CH_UTF16LE) ret = "UTF-16LE";
-       else if (ch == CH_UTF16BE) ret = "UTF-16BE";
-       else if (ch == CH_UNIX) ret = lp_unix_charset();
-       else if (ch == CH_DOS) ret = lp_dos_charset();
-       else if (ch == CH_DISPLAY) ret = lp_display_charset();
-       else if (ch == CH_UTF8) ret = "UTF8";
+       const char *ret;
+
+       switch (ch) {
+       case CH_UTF16LE:
+               ret = "UTF-16LE";
+               break;
+       case CH_UTF16BE:
+               ret = "UTF-16BE";
+               break;
+       case CH_UNIX:
+               ret = lp_unix_charset();
+               break;
+       case CH_DOS:
+               ret = lp_dos_charset();
+               break;
+       case CH_DISPLAY:
+               ret = lp_display_charset();
+               break;
+       case CH_UTF8:
+               ret = "UTF8";
+               break;
+       default:
+               ret = NULL;
+       }
 
 #if defined(HAVE_NL_LANGINFO) && defined(CODESET)
        if (ret && !strcmp(ret, "LOCALE")) {
@@ -558,7 +574,7 @@ bool convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
                return false;
        }
        if (srclen == 0) {
-               ob = ((ctx != NULL) ? talloc_strdup(ctx, "") : SMB_STRDUP(""));
+               ob = talloc_strdup(ctx, "");
                if (ob == NULL) {
                        errno = ENOMEM;
                        return false;
@@ -586,8 +602,7 @@ bool convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
                /* wrapped ! abort. */
                if (!conv_silent)
                        DEBUG(0, ("convert_string_talloc: destlen wrapped !\n"));
-               if (!ctx)
-                       SAFE_FREE(outbuf);
+               TALLOC_FREE(outbuf);
                errno = EOPNOTSUPP;
                return false;
        } else {
@@ -754,12 +769,12 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
        size_t size;
        smb_ucs2_t *buffer;
 
-       if (!push_ucs2_talloc(NULL, &buffer, src, &size)) {
+       if (!push_ucs2_talloc(talloc_tos(), &buffer, src, &size)) {
                return (size_t)-1;
        }
 
        if (!strupper_w(buffer) && (dest == src)) {
-               free(buffer);
+               TALLOC_FREE(buffer);
                return srclen;
        }
 
@@ -838,7 +853,7 @@ size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
        size_t size;
        smb_ucs2_t *buffer = NULL;
 
-       if (!convert_string_talloc(NULL, CH_UNIX, CH_UTF16LE, src, srclen,
+       if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_UTF16LE, src, srclen,
                                   (void **)(void *)&buffer, &size,
                                   True))
        {
@@ -952,7 +967,7 @@ size_t push_ascii_nstring(void *dest, const char *src)
        smb_ucs2_t *buffer;
 
        conv_silent = True;
-       if (!push_ucs2_talloc(NULL, &buffer, src, &buffer_len)) {
+       if (!push_ucs2_talloc(talloc_tos(), &buffer, src, &buffer_len)) {
                smb_panic("failed to create UCS2 buffer");
        }
 
@@ -1047,9 +1062,7 @@ size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len,
 
 /**
  * Copy a string from a dos codepage source to a unix char* destination.
- Talloc version.
- Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
- needs fixing. JRA).
+ * Talloc version.
  *
  * The resulting string in "dest" is always null terminated.
  *
@@ -1271,7 +1284,7 @@ static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
        }
 
        if (flags & STR_UPPER) {
-               tmpbuf = strupper_talloc(NULL, src);
+               tmpbuf = strupper_talloc(talloc_tos(), src);
                if (!tmpbuf) {
                        return (size_t)-1;
                }
@@ -1600,6 +1613,7 @@ size_t push_string_check_fn(const char *function, unsigned int line,
        return push_ascii(dest, src, dest_len, flags);
 }
 
+
 /**
  Copy a string from a char* src to a unicode or ascii
  dos codepage destination choosing unicode or ascii based on the 
@@ -1641,6 +1655,44 @@ size_t push_string_base(const char *function, unsigned int line,
        return push_ascii(dest, src, dest_len, flags);
 }
 
+/**
+ Copy a string from a char* src to a unicode or ascii
+ dos codepage destination choosing unicode or ascii based on the 
+ flags supplied
+ Return the number of bytes occupied by the string in the destination.
+ flags can have:
+  STR_TERMINATE means include the null termination.
+  STR_UPPER     means uppercase in the destination.
+  STR_ASCII     use ascii even with unicode packet.
+  STR_NOALIGN   means don't do alignment.
+ dest_len is the maximum length allowed in the destination. If dest_len
+ is -1 then no maxiumum is used.
+**/
+
+ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags)
+{
+       size_t ret;
+#ifdef DEVELOPER
+       /* We really need to zero fill here, not clobber
+        * region, as we want to ensure that valgrind thinks
+        * all of the outgoing buffer has been written to
+        * so a send() or write() won't trap an error.
+        * JRA.
+        */
+       memset(dest, '\0', dest_len);
+#endif
+
+       if (!(flags & STR_ASCII) && \
+           (flags & STR_UNICODE)) {
+               ret = push_ucs2(NULL, dest, src, dest_len, flags);
+       } else {
+               ret = push_ascii(dest, src, dest_len, flags);
+       }
+       if (ret == (size_t)-1) {
+               return -1;
+       }
+       return ret;
+}
 
 /**
  Copy a string from a unicode or ascii source (depending on
@@ -1823,3 +1875,64 @@ codepoint_t next_codepoint(const char *str, size_t *size)
        /* no other length is valid */
        return INVALID_CODEPOINT;
 }
+
+/*
+  push a single codepoint into a CH_UNIX string the target string must
+  be able to hold the full character, which is guaranteed if it is at
+  least 5 bytes in size. The caller may pass less than 5 bytes if they
+  are sure the character will fit (for example, you can assume that
+  uppercase/lowercase of a character will not add more than 1 byte)
+
+  return the number of bytes occupied by the CH_UNIX character, or
+  -1 on failure
+*/
+_PUBLIC_ ssize_t push_codepoint(char *str, codepoint_t c)
+{
+       smb_iconv_t descriptor;
+       uint8_t buf[4];
+       size_t ilen, olen;
+       const char *inbuf;
+       
+       if (c < 128) {
+               *str = c;
+               return 1;
+       }
+
+       lazy_initialize_conv();
+
+       descriptor = conv_handles[CH_UNIX][CH_UTF16LE];
+       if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
+               return -1;
+       }
+
+       if (c < 0x10000) {
+               ilen = 2;
+               olen = 5;
+               inbuf = (char *)buf;
+               SSVAL(buf, 0, c);
+               smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
+               if (ilen != 0) {
+                       return -1;
+               }
+               return 5 - olen;
+       }
+
+       c -= 0x10000;
+
+       buf[0] = (c>>10) & 0xFF;
+       buf[1] = (c>>18) | 0xd8;
+       buf[2] = c & 0xFF;
+       buf[3] = ((c>>8) & 0x3) | 0xdc;
+
+       ilen = 4;
+       olen = 5;
+       inbuf = (char *)buf;
+
+       smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
+       if (ilen != 0) {
+               return -1;
+       }
+       return 5 - olen;
+}
+
+