Browse Source

smb_iconv: fix conv if dst_len is more than 2x bigger

Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
Thomas Guillem 10 years ago
parent
commit
cd7c13d76f
1 changed files with 29 additions and 16 deletions
  1. 29 16
      src/smb_utils.c

+ 29 - 16
src/smb_utils.c

@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 #include "config.h"
 
@@ -50,12 +51,10 @@ static const char *current_encoding()
 }
 
 static size_t smb_iconv(const char *src, size_t src_len, char **dst,
-                        size_t dst_len, const char *src_enc,
-                        const char *dst_enc)
+                        const char *src_enc, const char *dst_enc)
 {
     iconv_t   ic;
-    char      *out;
-    size_t    outleft;
+    size_t    ret = 0;
 
     assert(src != NULL && dst != NULL && src_enc != NULL && dst_enc != NULL);
 
@@ -72,28 +71,42 @@ static size_t smb_iconv(const char *src, size_t src_len, char **dst,
         *dst = NULL;
         return (0);
     }
-
-    outleft = dst_len; // The utf-16 str is at most 2x bigger than the utf-8 one. (i think ?)
-    out     = *dst = malloc(outleft);
-
-    assert(out != NULL);
-    iconv(ic, (char **)&src, &src_len, &out, &outleft);
+    for (unsigned mul = 4; mul < 16; mul++)
+    {
+        size_t outlen = mul * src_len;
+        char *out = malloc(outlen);
+
+        const char *inp = src;
+        size_t inb = src_len;
+        char *outp = out;
+        size_t outb = outlen;
+
+        if (!out)
+            break;
+        if (iconv(ic, (char **)&inp, &inb, &outp, &outb) != (size_t)(-1)) {
+            ret = outlen - outb;
+            *dst = out;
+            break;
+        }
+        free(out);
+        if (errno != E2BIG)
+            break;
+    }
     iconv_close(ic);
 
-    if (src_len > 0)
-      BDSM_dbg("iconv: Some character were lost at encoding/decoding");
-
-    return (dst_len - outleft);
+    if (ret == 0)
+        *dst = NULL;
+    return (ret);
 }
 
 size_t      smb_to_utf16(const char *src, size_t src_len, char **dst)
 {
-    return (smb_iconv(src, src_len, dst, src_len * 2,
+    return (smb_iconv(src, src_len, dst,
                       current_encoding(), "UCS-2LE"));
 }
 
 size_t      smb_from_utf16(const char *src, size_t src_len, char **dst)
 {
-    return (smb_iconv(src, src_len, dst, src_len,
+    return (smb_iconv(src, src_len, dst,
                       "UCS-2LE", current_encoding()));
 }