From ab308bea3175dd21139b7b842b6de56bf88d8b1c Mon Sep 17 00:00:00 2001
From: Klaus Schmidinger <vdr@tvdr.de>
Date: Thu, 14 May 2020 21:21:03 +0200
Subject: Fixed handling multi part ExtendedEventDescriptors where only the
 first part contains information about the character table

---
 libsi/descriptor.c |  14 ++++---
 libsi/si.c         | 112 +++++++++++++++++++++++++++++------------------------
 libsi/si.h         |  13 +++++--
 3 files changed, 79 insertions(+), 60 deletions(-)

(limited to 'libsi')

diff --git a/libsi/descriptor.c b/libsi/descriptor.c
index 6b00fc77..a94c0035 100644
--- a/libsi/descriptor.c
+++ b/libsi/descriptor.c
@@ -6,7 +6,7 @@
  *   the Free Software Foundation; either version 2 of the License, or     *
  *   (at your option) any later version.                                   *
  *                                                                         *
- *   $Id: descriptor.c 4.1 2019/03/15 16:12:43 kls Exp $
+ *   $Id: descriptor.c 4.2 2020/05/14 21:21:03 kls Exp $
  *                                                                         *
  ***************************************************************************/
 
@@ -90,17 +90,21 @@ char *ExtendedEventDescriptors::getText(const char *separation1, const char *sep
 }
 
 char *ExtendedEventDescriptors::getText(char *buffer, int size, const char *separation1, const char *separation2) {
+   int tmpsize = size;
+   char tmpbuf[tmpsize];
+   const char *fromCode = NULL;
    int index=0, len;
    for (int i=0;i<length;i++) {
       ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
       if (!d)
          continue;
-      d->text.getText(buffer+index, size);
-      len = strlen(buffer+index);
+      d->text.getText(tmpbuf+index, tmpsize, &fromCode);
+      len = strlen(tmpbuf+index);
       index += len;
-      size -= len;
+      tmpsize -= len;
    }
-
+   index = convertCharacterTable(tmpbuf, strlen(tmpbuf), buffer, size, fromCode);
+   size -= index;
    int sepLen1 = strlen(separation1);
    int sepLen2 = strlen(separation2);
    bool separated = false;
diff --git a/libsi/si.c b/libsi/si.c
index e51770ab..c294c2fc 100644
--- a/libsi/si.c
+++ b/libsi/si.c
@@ -6,7 +6,7 @@
  *   the Free Software Foundation; either version 2 of the License, or     *
  *   (at your option) any later version.                                   *
  *                                                                         *
- *   $Id: si.c 3.3 2015/02/10 13:42:41 kls Exp $
+ *   $Id: si.c 4.1 2020/05/14 21:21:03 kls Exp $
  *                                                                         *
  ***************************************************************************/
 
@@ -230,14 +230,14 @@ char *String::getText() {
    return data;
 }
 
-char *String::getText(char *buffer, int size) {
+char *String::getText(char *buffer, int size, const char **fromCode) {
    int len=getLength();
    if (len < 0 || len >= size) {
       strncpy(buffer, "text error", size);
       buffer[size-1] = 0;
       return buffer;
    }
-   decodeText(buffer, size);
+   decodeText(buffer, size, fromCode);
    return buffer;
 }
 
@@ -386,9 +386,25 @@ const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *i
    return cs;
 }
 
-bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode)
+// A similar version is used in VDR/tools.c:
+static int Utf8CharLen(const char *s)
+{
+  if (SystemCharacterTableIsSingleByte)
+     return 1;
+#define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
+  if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
+     return 2;
+  if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
+     return 3;
+  if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
+     return 4;
+  return 1;
+}
+
+size_t convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode)
 {
-  if (SystemCharacterTable) {
+  char *result = to;
+  if (SystemCharacterTable && fromCode) {
      iconv_t cd = iconv_open(SystemCharacterTable, fromCode);
      if (cd != (iconv_t)-1) {
         char *fromPtr = (char *)from;
@@ -407,29 +423,44 @@ bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t
         }
         *to = 0;
         iconv_close(cd);
-        return true;
      }
   }
-  return false;
-}
-
-// A similar version is used in VDR/tools.c:
-static int Utf8CharLen(const char *s)
-{
-  if (SystemCharacterTableIsSingleByte)
-     return 1;
-#define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
-  if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
-     return 2;
-  if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
-     return 3;
-  if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
-     return 4;
-  return 1;
+  else {
+     size_t len = fromLength;
+     if (len >= toLength)
+        len = toLength - 1;
+     strncpy(to, from, len);
+     to[len] = 0;
+  }
+  // Handle control codes:
+  to = result;
+  size_t len = strlen(to);
+  while (len > 0) {
+     int l = Utf8CharLen(to);
+     if (l <= 2) {
+        unsigned char *p = (unsigned char *)to;
+        if (l == 2 && *p == 0xC2) // UTF-8 sequence
+           p++;
+        bool Move = true;
+        switch (*p) {
+          case 0x8A: *to = '\n'; break;
+          case 0xA0: *to = ' ';  break;
+          default:   Move = false;
+        }
+        if (l == 2 && Move) {
+           memmove(p, p + 1, len - 1); // we also copy the terminating 0!
+           len -= 1;
+           l = 1;
+        }
+     }
+     to += l;
+     len -= l;
+  }
+  return strlen(result);
 }
 
 // originally from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de>
-void String::decodeText(char *buffer, int size) {
+void String::decodeText(char *buffer, int size, const char **fromCode) {
    const unsigned char *from=data.getData(0);
    char *to=buffer;
    int len=getLength();
@@ -437,38 +468,17 @@ void String::decodeText(char *buffer, int size) {
       *to = '\0';
       return;
    }
-   bool singleByte;
-   const char *cs = getCharacterTable(from, len, &singleByte);
-   if (singleByte && SystemCharacterTableIsSingleByte || !convertCharacterTable((const char *)from, len, to, size, cs)) {
+   const char *cs = getCharacterTable(from, len);
+   if (fromCode) {
       if (len >= size)
          len = size - 1;
-      strncpy(to, (const char *)from, len);
-      to[len] = 0;
+      strncpy(buffer, (const char *)from, len);
+      buffer[len] = 0;
+      if (!*fromCode)
+         *fromCode = cs;
    }
    else
-      len = strlen(to); // might have changed
-   // Handle control codes:
-   while (len > 0) {
-      int l = Utf8CharLen(to);
-      if (l <= 2) {
-         unsigned char *p = (unsigned char *)to;
-         if (l == 2 && *p == 0xC2) // UTF-8 sequence
-            p++;
-         bool Move = true;
-         switch (*p) {
-           case 0x8A: *to = '\n'; break;
-           case 0xA0: *to = ' ';  break;
-           default:   Move = false;
-         }
-         if (l == 2 && Move) {
-            memmove(p, p + 1, len - 1); // we also copy the terminating 0!
-            len -= 1;
-            l = 1;
-         }
-      }
-      to += l;
-      len -= l;
-   }
+      convertCharacterTable((const char *)from, len, to, size, cs);
 }
 
 void String::decodeText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) {
diff --git a/libsi/si.h b/libsi/si.h
index e70de685..c5f426ef 100644
--- a/libsi/si.h
+++ b/libsi/si.h
@@ -6,7 +6,7 @@
  *   the Free Software Foundation; either version 2 of the License, or     *
  *   (at your option) any later version.                                   *
  *                                                                         *
- *   $Id: si.h 3.4 2015/02/10 13:54:28 kls Exp $
+ *   $Id: si.h 4.1 2020/05/14 21:21:03 kls Exp $
  *                                                                         *
  ***************************************************************************/
 
@@ -508,7 +508,10 @@ public:
    //so the maximum there is 256.
    //returns the given buffer for convenience.
    //The emphasis marks 0x86 and 0x87 are still available.
-   char *getText(char *buffer, int size);
+   //If fromCode is given, the string will be copied into buffer in its raw form,
+   //without conversion, and he code table of the string is returned in this variable
+   //if it is NULL.
+   char *getText(char *buffer, int size, const char **fromCode = NULL);
    //The same semantics as for getText(char*) apply.
    //The short version of the text according to ETSI TR 101 211 (chapter 4.6)
    //will be written into the shortVersion buffer (which should, therefore, have the same
@@ -518,7 +521,7 @@ public:
    char *getText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion);
 protected:
    virtual void Parse() {}
-   void decodeText(char *buffer, int size);
+   void decodeText(char *buffer, int size, const char **fromCode = NULL);
    void decodeText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion);
 };
 
@@ -534,7 +537,9 @@ bool SetSystemCharacterTable(const char *CharacterTable);
 // default ISO6937 is returned. If a table can be determined, the buffer
 // and length are adjusted accordingly.
 const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte = NULL);
-bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode);
+// Copies 'from' to 'to' and converts characters according to 'fromCode', if given.
+// Returns the length of the resulting string.
+size_t convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode);
 bool systemCharacterTableIsSingleByte(void);
 
 } //end of namespace
-- 
cgit v1.2.3