]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
intlconv: add intlconv_to_utf8() and use it in dvb_support.c also fixes #2319
authorJaroslav Kysela <perex@perex.cz>
Thu, 2 Oct 2014 11:36:31 +0000 (13:36 +0200)
committerJaroslav Kysela <perex@perex.cz>
Thu, 2 Oct 2014 11:36:31 +0000 (13:36 +0200)
src/input/mpegts/dvb_support.c
src/intlconv.c
src/intlconv.h

index c8c6bcff32e9c931d07fbb39d845f0a4dfe67f1d..36dce6773b4a0e12d3be56c68beec1f0f39095e5 100644 (file)
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
-#include <iconv.h>
 
 #include "tvheadend.h"
 #include "dvb.h"
 #include "dvb_charset_tables.h"
 #include "input.h"
+#include "intlconv.h"
 
 static int convert_iso_8859[16] = {
   -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 11, 12, 13
@@ -40,32 +40,14 @@ static int convert_iso_8859[16] = {
 #define convert_ucs2 16
 #define convert_gb   17
 
-static inline int code_convert(const char *from_charset,const char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t *outlen)
-{
-    iconv_t cd;
-
-    char **pin = &inbuf;
-    char **pout = &outbuf;
-
-    cd = iconv_open(to_charset,from_charset);
-    if (cd==0) return -1;
-    memset(outbuf,0,*outlen);
-    if (iconv(cd,pin,&inlen,pout,outlen)==-1) return -1;
-    iconv_close(cd);
-    return 0;
-}
-
-static inline int gb2u(char *inbuf,int inlen,char *outbuf,size_t *outlen)
-{
-    return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
-}
-
 static inline size_t conv_gb(const uint8_t *src, size_t srclen,
                              char *dst, size_t *dstlen)
 {
-    size_t len=*dstlen;
-    gb2u((char *)src,srclen,dst,dstlen);
-    dst+=len-*dstlen;
+    ssize_t len;
+    len = intlconv_to_utf8(dst, *dstlen, "gb2312", (char *)src, srclen);
+    if (len < 0 || len > *dstlen)
+      return -1;
+    *dstlen -= len;
     return 0;
 }
 
index 985b77f38a9ad9185a0a325c7f3bdc748842a4fc..6e198a38dfec7de7479d4e5f68dc83f5d76ae766 100644 (file)
@@ -12,10 +12,27 @@ static RB_HEAD(,intlconv_cache) intlconv_all;
 static intlconv_cache_t        *intlconv_last_ic;
 pthread_mutex_t                 intlconv_lock;
 
+static RB_HEAD(,intlconv_cache) intlconv_src_all;
+static intlconv_cache_t        *intlconv_last_src_ic;
+pthread_mutex_t                 intlconv_lock_src;
+
+static inline size_t
+tvh_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft,
+                      char **outbuf, size_t *outbytesleft)
+{
+#ifdef PLATFORM_FREEBSD
+  return iconv(cd, (const char **)inbuf, inbytesleft,
+                   (const char **)outbuf, outbytesleft);
+#else
+  return iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft);
+#endif
+}
+
 void
 intlconv_init( void )
 {
   pthread_mutex_init(&intlconv_lock, NULL);
+  pthread_mutex_init(&intlconv_lock_src, NULL);
 }
 
 void
@@ -31,6 +48,13 @@ intlconv_done( void )
     RB_REMOVE(&intlconv_all, ic, ic_link);
     free(ic);
   }
+  intlconv_last_src_ic = NULL;
+  while ((ic = RB_FIRST(&intlconv_src_all)) != NULL) {
+    iconv_close(ic->ic_handle);
+    free(ic->ic_charset_id);
+    RB_REMOVE(&intlconv_src_all, ic, ic_link);
+    free(ic);
+  }
   pthread_mutex_unlock(&intlconv_lock);
 }
 
@@ -121,18 +145,16 @@ intlconv_utf8( char *dst, size_t dst_size,
     ic->ic_handle = c;
     RB_INSERT_SORTED(&intlconv_all, ic, ic_link, intlconv_cmp);
   }
+  intlconv_last_ic = ic;
 found:
+  pthread_mutex_unlock(&intlconv_lock);
   inbuf       = (char **)&src_utf8;
   inbuf_left  = strlen(src_utf8);
   outbuf      = &dst;
   outbuf_left = dst_size;
-  res = iconv(ic->ic_handle, inbuf, &inbuf_left, outbuf, &outbuf_left);
-  if (res == -1) {
+  res = tvh_iconv(ic->ic_handle, inbuf, &inbuf_left, outbuf, &outbuf_left);
+  if (res == -1)
     res = -errno;
-  } else {
-    intlconv_last_ic = ic;
-  }
-  pthread_mutex_unlock(&intlconv_lock);
   if (res >= 0)
     res = dst_size - outbuf_left;
   return res;
@@ -161,6 +183,65 @@ intlconv_utf8safestr( const char *dst_charset_id,
   return res;
 }
 
+ssize_t
+intlconv_to_utf8( char *dst, size_t dst_size,
+                  const char *src_charset_id,
+                  const char *src, size_t src_size )
+{
+  intlconv_cache_t templ, *ic;
+  char **inbuf, **outbuf;
+  size_t inbuf_left, outbuf_left;
+  ssize_t res;
+
+  if (src_charset_id == NULL) {
+    strncpy(dst, src, dst_size);
+    dst[dst_size - 1] = '\0';
+    return strlen(dst);
+  }
+  templ.ic_charset_id = (char *)src_charset_id;
+  pthread_mutex_lock(&intlconv_lock_src);
+  if (intlconv_last_src_ic &&
+      strcmp(intlconv_last_src_ic->ic_charset_id, src_charset_id) == 0) {
+    ic = intlconv_last_src_ic;
+    goto found;
+  }
+  ic = RB_FIND(&intlconv_src_all, &templ, ic_link, intlconv_cmp);
+  if (!ic) {
+    iconv_t c = iconv_open("UTF-8", src_charset_id);
+    if ((iconv_t)-1 == c) {
+      pthread_mutex_unlock(&intlconv_lock_src);
+      return -EIO;
+    }
+    ic = malloc(sizeof(*ic));
+    if (ic == NULL) {
+      pthread_mutex_unlock(&intlconv_lock_src);
+      return -ENOMEM;
+    }
+    ic->ic_charset_id = strdup(src_charset_id);
+    if (ic->ic_charset_id == NULL) {
+      pthread_mutex_unlock(&intlconv_lock_src);
+      free(ic);
+      iconv_close(c);
+      return -ENOMEM;
+    }
+    ic->ic_handle = c;
+    RB_INSERT_SORTED(&intlconv_src_all, ic, ic_link, intlconv_cmp);
+  }
+  intlconv_last_src_ic = ic;
+found:
+  pthread_mutex_unlock(&intlconv_lock_src);
+  inbuf       = (char **)&src;
+  inbuf_left  = src_size;
+  outbuf      = &dst;
+  outbuf_left = dst_size;
+  res = tvh_iconv(ic->ic_handle, inbuf, &inbuf_left, outbuf, &outbuf_left);
+  if (res == -1)
+    res = -errno;
+  if (res >= 0)
+    res = dst_size - outbuf_left;
+  return res;
+}
+
 /*
  *
  */
index 1b57f6e0a91b581f26df067e99eee957e74009ae..53decb7105cbbb5c6a12cd1aac1bbfb3365be8ef 100644 (file)
@@ -38,4 +38,9 @@ intlconv_utf8safestr( const char *dst_charset_id,
                       const char *src_utf8,
                       size_t max_size );
 
+ssize_t
+intlconv_to_utf8( char *dst, size_t dst_size,
+                  const char *src_charset_id,
+                  const char *src, size_t src_size );
+
 #endif /* INTLCONV_H_ */