summaryrefslogtreecommitdiff
path: root/source3/lib/charcnv.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib/charcnv.c')
-rw-r--r--source3/lib/charcnv.c92
1 files changed, 82 insertions, 10 deletions
diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c
index 5f9392b620..5bd58e3031 100644
--- a/source3/lib/charcnv.c
+++ b/source3/lib/charcnv.c
@@ -184,14 +184,18 @@ static size_t convert_string_internal(charset_t from, charset_t to,
}
}
+
if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
if (!conv_silent)
DEBUG(0,("convert_string_internal: Conversion not supported.\n"));
- goto use_as_is;
+ return 0;
}
i_len=srclen;
o_len=destlen;
+
+ again:
+
retval = smb_iconv(descriptor, (char **)&inbuf, &i_len, &outbuf, &o_len);
if(retval==(size_t)-1) {
const char *reason="unknown error";
@@ -227,12 +231,76 @@ static size_t convert_string_internal(charset_t from, charset_t to,
use_as_is:
- /* conversion not supported, use as is */
+ /*
+ * Conversion not supported. This is actually an error, but there are so
+ * many misconfigured iconv systems and smb.conf's out there we can't just
+ * fail. Do a very bad conversion instead.... JRA.
+ */
+
{
- size_t len = MIN(srclen,destlen);
- if (len)
- memcpy(dest,src,len);
- return len;
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ if (from == CH_UCS2 && to != CH_UCS2) {
+ /* Can't convert from ucs2 to multibyte. Just truncate this char to ascii. */
+ if (i_len < 2)
+ return destlen - o_len;
+ if (i_len >= 2) {
+ *outbuf = inbuf[0];
+
+ outbuf++;
+ o_len--;
+
+ inbuf += 2;
+ i_len -= 2;
+ }
+
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else if (from != CH_UCS2 && to == CH_UCS2) {
+ /* Can't convert to ucs2 - just widen by adding zero. */
+ if (o_len < 2)
+ return destlen;
+ outbuf[0] = inbuf[0];
+ outbuf[1] = '\0';
+
+ inbuf++;
+ i_len--;
+
+ outbuf += 2;
+ o_len -= 2;
+
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else if (from != CH_UCS2 && to != CH_UCS2) {
+ /* Failed multibyte to multibyte. Just copy 1 char and
+ try again. */
+ outbuf[0] = inbuf[0];
+
+ inbuf++;
+ i_len--;
+
+ outbuf++;
+ o_len--;
+
+ if (o_len == 0 || i_len == 0)
+ return destlen - o_len;
+
+ /* Keep trying with the next char... */
+ goto again;
+
+ } else {
+ /* Keep compiler happy.... */
+ return destlen - o_len;
+ }
}
}
@@ -241,9 +309,9 @@ static size_t convert_string_internal(charset_t from, charset_t to,
* Fast path version - handles ASCII first.
*
* @param src pointer to source string (multibyte or singlebyte)
- * @param srclen length of the source string in bytes
+ * @param srclen length of the source string in bytes, or -1 for nul terminated.
* @param dest pointer to destination string (multibyte or singlebyte)
- * @param destlen maximal length allowed for string
+ * @param destlen maximal length allowed for string - *NEVER* -1.
* @returns the number of bytes occupied in the destination
*
* Ensure the srclen contains the terminating zero.
@@ -257,11 +325,15 @@ size_t convert_string(charset_t from, charset_t to,
void *dest, size_t destlen)
{
/*
- * NB. We deliberately don't do a strlen here is srclen == -1.
+ * NB. We deliberately don't do a strlen here if srclen == -1.
* This is very expensive over millions of calls and is taken
* care of in the slow path in convert_string_internal. JRA.
*/
+#ifdef DEVELOPER
+ SMB_ASSERT(destlen != (size_t)-1);
+#endif
+
if (srclen == 0)
return 0;
@@ -302,7 +374,7 @@ size_t convert_string(charset_t from, charset_t to,
unsigned char lastp;
/* If all characters are ascii, fast path here. */
- while ((slen >= 2) && dlen) {
+ while (((slen == (size_t)-1) || (slen >= 2)) && dlen) {
if (((lastp = *p) <= 0x7f) && (p[1] == 0)) {
*q++ = *p;
if (slen != (size_t)-1) {