From ab308bea3175dd21139b7b842b6de56bf88d8b1c Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Thu, 14 May 2020 21:21:03 +0200 Subject: [PATCH] Fixed handling multi part ExtendedEventDescriptors where only the first part contains information about the character table --- CONTRIBUTORS | 2 + HISTORY | 4 +- libsi/descriptor.c | 14 ++++-- libsi/si.c | 112 ++++++++++++++++++++++++--------------------- libsi/si.h | 13 ++++-- 5 files changed, 84 insertions(+), 61 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 6bd3af04..f085eeba 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3589,6 +3589,8 @@ Helmut Binder for helping with the implementation of retuning if the received transponder's SDT doesn't contain the expected values for NID and TID for adding the language code for Bulgarian + for a patch that was used as a base for fixing handling multi part ExtendedEventDescriptors + where only the first part contains information about the character table Ulrich Eckhardt for reporting a problem with shutdown after user inactivity in case a plugin is diff --git a/HISTORY b/HISTORY index b136e7c2..fafad735 100644 --- a/HISTORY +++ b/HISTORY @@ -9420,7 +9420,7 @@ Video Disk Recorder Revision History - Fixed handling the S2SatelliteDeliverySystemDescriptor for transponders broadcasting in "backwards compatibility mode" according to ETSI EN 300 468 (thanks to Onur Sentürk). -2020-05-11: +2020-05-14: - Fixed moving channels between number groups in SVDRP's MOVC command and the Channels menu, in case a channel is moved to a higher number and into a numbered group @@ -9432,3 +9432,5 @@ Video Disk Recorder Revision History - The SVDRP command DELC now also accepts a channel id (suggested by Manuel Reimer). - Fixed dropping capabilities in case cap_sys_time is not available. - Added the language code for Bulgarian (thanks to Helmut Binder). +- Fixed handling multi part ExtendedEventDescriptors where only the first part + contains information about the character table (based on a patch from Helmut Binder). 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;itext.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 (SystemCharacterTable) { + 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) +{ + 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 -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