Fixed handling itemized texts in EPG data

This commit is contained in:
Klaus Schmidinger 2004-03-07 11:13:54 +01:00
parent e070d5462c
commit 823081b59e
8 changed files with 300 additions and 80 deletions

View File

@ -944,6 +944,7 @@ Thomas Bergwinkl <Thomas.Bergwinkl@t-online.de>
Stéphane Esté-Gracias <sestegra@free.fr>
for fixing a typo in libsi/si.h
for fixing some descriptor handling in 'libsi'
for pointing out a problem with "itemized" texts in EPG data
Marc Hoppe <MarcHoppe@gmx.de>
for fixing handling the current menu item

View File

@ -2725,3 +2725,5 @@ Video Disk Recorder Revision History
- Fixed handling timers in VPS margin if the EPG scan is turned on (the EPG scan
switched the device away from the channel, so it wouldn't see the change of
the running status).
- Fixed handling "itemized" texts in EPG data (thanks to Stéphane Esté-Gracias
for pointing out this problem, and Marcel Wiesweg for improving 'libsi').

4
eit.c
View File

@ -8,7 +8,7 @@
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
*
* $Id: eit.c 1.90 2004/03/06 14:24:22 kls Exp $
* $Id: eit.c 1.91 2004/03/07 10:36:57 kls Exp $
*/
#include "eit.h"
@ -191,7 +191,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
}
if (ExtendedEventDescriptors) {
char buffer[ExtendedEventDescriptors->getMaximumTextLength()];
pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer));
pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, ": "));
}
}
delete ExtendedEventDescriptors;

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: descriptor.c 1.7 2004/03/05 15:17:33 kls Exp $
* $Id: descriptor.c 1.8 2004/03/07 11:07:57 kls Exp $
* *
***************************************************************************/
@ -60,13 +60,13 @@ void ExtendedEventDescriptor::Item::Parse() {
item.setData(data+offset, mid->item_length);
}
int ExtendedEventDescriptors::getTextLength() {
/*int ExtendedEventDescriptors::getTextLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ret+=d->text.getLength()+1; //plus a blank
ret+=d->text.getLength();
ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it);
@ -76,28 +76,18 @@ int ExtendedEventDescriptors::getTextLength() {
}
}
return ret;
}
}*/
//is there a case where this function does not return the same as getTextLength?
int ExtendedEventDescriptors::getMaximumTextLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ret+=d->text.getLength()+1; //plus a blank
ret+=d->itemLoop.getLength();
}
return ret;
return getMaximumTextPlainLength()+getMaximumTextItemizedLength();
}
char *ExtendedEventDescriptors::getText() {
char *ExtendedEventDescriptors::getText(const char *separation1, const char *separation2) {
char *text=new char[getMaximumTextLength()];
return getText(text);
return getText(text, separation1, separation2);
}
//appends the Strings of every Descriptor in the group
char *ExtendedEventDescriptors::getText(char *buffer) {
char *ExtendedEventDescriptors::getText(char *buffer, const char *separation1, const char *separation2) {
int index=0, len;
char tempbuf[256];
for (int i=0;i<length;i++) {
@ -110,30 +100,161 @@ char *ExtendedEventDescriptors::getText(char *buffer) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
}
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it);
item.item.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
item.itemDescription.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
strcpy(buffer+index, separation1);
index += strlen(separation1);
item.item.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
strcpy(buffer+index, separation2);
index += strlen(separation2);
}
}
buffer[index]='\0';
return buffer;
}
int ExtendedEventDescriptors::getMaximumTextPlainLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ret+=d->text.getLength();
}
return ret;
}
char *ExtendedEventDescriptors::getTextPlain() {
char *text=new char[getMaximumTextPlainLength()];
return getText(text);
}
char *ExtendedEventDescriptors::getTextPlain(char *buffer) {
int index=0, len;
char tempbuf[256];
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
d->text.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
}
buffer[index]='\0';
return buffer;
}
int ExtendedEventDescriptors::getMaximumTextItemizedLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
//the size for the two separating characters is included ;-)
ret+=d->itemLoop.getLength();
}
return ret;
}
char *ExtendedEventDescriptors::getTextItemized(const char *separation1, const char *separation2) {
char *text=new char[getMaximumTextItemizedLength()];
return getText(text, separation1, separation2);
}
char *ExtendedEventDescriptors::getTextItemized(char *buffer, const char *separation1, const char *separation2) {
int index=0, len;
char tempbuf[256];
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it);
item.itemDescription.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
strcpy(buffer+index, separation1);
index += strlen(separation1);
item.item.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
strcpy(buffer+index, separation2);
index += strlen(separation2);
}
}
buffer[index]='\0';
return buffer;
}
//returns the itemized text pair by pair. Maximum length for buffers is 256.
//Return value is false if and only if the end of the list is reached.
bool ExtendedEventDescriptors::getTextItemized(Loop::Iterator &it, bool &valid, char *itemDescription, char *itemText) {
//The iterator has to store two values: The descriptor index (4bit)
//and the item loop index (max overall length 256, min item length 16 => max number 128 => 7bit)
valid=false;
int index=(it.i & 0x780) >> 7; // 0x780 == 1111 000 0000
it.i &= 0x7F; //0x7F == 111 1111
for (;index<length;index++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[index];
if (!d)
continue;
ExtendedEventDescriptor::Item item;
if (d->itemLoop.hasNext(it)) {
item=d->itemLoop.getNext(it);
item.item.getText(itemDescription);
item.itemDescription.getText(itemText);
valid=true;
} else {
it.reset();
continue;
}
}
it.i &= 0x7F;
it.i |= (index & 0xF) << 7; //0xF == 1111
return index<length;
}
int TimeShiftedEventDescriptor::getReferenceServiceId() const {
return HILO(s->reference_service_id);
}

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: descriptor.h 1.6 2004/02/22 10:16:47 kls Exp $
* $Id: descriptor.h 1.7 2004/03/07 11:13:54 kls Exp $
* *
***************************************************************************/
@ -50,14 +50,29 @@ private:
class ExtendedEventDescriptors : public DescriptorGroup {
public:
//don't use
int getTextLength();
//really fast
int getMaximumTextLength();
//Returns a concatenated version of first the non-itemized and then the itemized text
//same semantics as with SI::String
char *getText();
char *getText(const char *separation1="\t", const char *separation2="\n");
//buffer must at least be getTextLength(), getMaximumTextLength() is a good choice
char *getText(char *buffer);
char *getText(char *buffer, const char *separation1="\t", const char *separation2="\n");
//these only return the non-itemized text fields in concatenated form
int getMaximumTextPlainLength();
char *getTextPlain();
char *getTextPlain(char *buffer);
//these only return the itemized text fields in concatenated form.
//Between the description and the text the separation1 character is used,
//separation2 used between two pairs. Example:
//Director\tSteven Spielberg\nActor\tMichael Mendl\n
int getMaximumTextItemizedLength();
char *getTextItemized(const char *separation1="\t", const char *separation2="\n");
char *getTextItemized(char *buffer, const char *separation1="\t", const char *separation2="\n");
//returns the itemized text pair by pair. Maximum length for buffers is 256.
//Return value is false if and only if the end of the list is reached.
//The argument valid indicates whether the buffers contain valid content.
bool getTextItemized(Loop::Iterator &it, bool &valid, char *itemDescription, char *itemText);
};
class TimeShiftedEventDescriptor : public Descriptor {

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: si.c 1.8 2004/02/22 10:14:12 kls Exp $
* $Id: si.c 1.9 2004/03/07 10:50:09 kls Exp $
* *
***************************************************************************/
@ -103,7 +103,7 @@ DescriptorTag Descriptor::getDescriptorTag(const unsigned char *d) {
Descriptor *DescriptorLoop::getNext(Iterator &it) {
if (it.i<getLength()) {
return createDescriptor(it.i);
return createDescriptor(it.i, true);
}
return 0;
}
@ -115,19 +115,18 @@ Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag tag, bool return
const unsigned char *end=p+getLength();
while (p < end) {
if (Descriptor::getDescriptorTag(p) == tag) {
d=createDescriptor(it.i);
break;
d=createDescriptor(it.i, returnUnimplemetedDescriptor);
if (d)
break;
}
it.i+=Descriptor::getLength(p);
p+=Descriptor::getLength(p);
}
}
if (d && d->getDescriptorTag()==UnimplementedDescriptorTag)
return returnUnimplemetedDescriptor ? d : 0;
return d;
}
Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor) {
Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplementedDescriptor) {
Descriptor *d=0;
if (it.i<getLength()) {
const unsigned char *p=data.getData(it.i);
@ -135,27 +134,38 @@ Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int array
while (p < end) {
for (int u=0; u<arrayLength;u++)
if (Descriptor::getDescriptorTag(p) == tags[u]) {
d=createDescriptor(it.i);
d=createDescriptor(it.i, returnUnimplementedDescriptor);
break;
}
if (d)
break;
break; //length is added to it.i by createDescriptor, break here
it.i+=Descriptor::getLength(p);
p+=Descriptor::getLength(p);
}
}
if (d && d->getDescriptorTag()==UnimplementedDescriptorTag)
return returnUnimplemetedDescriptor ? d : 0;
return d;
}
Descriptor *DescriptorLoop::createDescriptor(int &i) {
Descriptor *d=Descriptor::getDescriptor(data+i, domain);
Descriptor *DescriptorLoop::createDescriptor(int &i, bool returnUnimplemetedDescriptor) {
Descriptor *d=Descriptor::getDescriptor(data+i, domain, returnUnimplemetedDescriptor);
if (!d)
return 0;
i+=d->getLength();
d->CheckParse();
return d;
}
int DescriptorLoop::getNumberOfDescriptors() {
const unsigned char *p=data.getData();
const unsigned char *end=p+getLength();
int count=0;
while (p < end) {
count++;
p+=Descriptor::getLength(p);
}
return count;
}
DescriptorGroup::DescriptorGroup(bool del) {
array=0;
length=0;
@ -211,6 +221,16 @@ char *String::getText(char *buffer) {
return buffer;
}
//taken from VDR, Copyright Klaus Schmidinger <kls@cadsoft.de>
char *String::getText(char *buffer, char *shortVersion) {
if (getLength() < 0 || getLength() >4095) {
strncpy(buffer, "text error", getLength()+1);
return buffer;
}
decodeText(buffer, shortVersion);
return buffer;
}
//taken from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de>
void String::decodeText(char *buffer) {
const unsigned char *from=data.getData(0);
@ -228,18 +248,47 @@ void String::decodeText(char *buffer) {
if ( ((' ' <= *from) && (*from <= '~'))
|| (*from == '\n')
|| (0xA0 <= *from)
|| (*from == 0x86 || *from == 0x87)
)
*to++ = *from;
else if (*from == 0x8A)
*to++ = '\n';
else if (*from == 0x86 || *from == 0x87) //&& !(GDT_NAME_DESCRIPTOR & type))
*to++ = *from;
from++;
}
*to = '\0';
}
Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain) {
void String::decodeText(char *buffer, char *shortVersion) {
const unsigned char *from=data.getData(0);
char *to=buffer;
char *toShort=shortVersion;
int IsShortName=0;
for (int i = 0; i < getLength(); i++) {
if (*from == 0)
break;
if ( ((' ' <= *from) && (*from <= '~'))
|| (*from == '\n')
|| (0xA0 <= *from)
)
{
*to++ = *from;
if (IsShortName)
*toShort++ = *from;
}
else if (*from == 0x8A)
*to++ = '\n';
else if (*from == 0x86)
IsShortName++;
else if (*from == 0x87)
IsShortName--;
from++;
}
*to = '\0';
*toShort = '\0';
}
Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor) {
Descriptor *d=0;
switch (domain) {
case SI:
@ -383,6 +432,8 @@ Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain)
case AdaptationFieldDataDescriptorTag:
case TransportStreamDescriptorTag:
default:
if (!returnUnimplemetedDescriptor)
return 0;
d=new UnimplementedDescriptor();
break;
}
@ -417,6 +468,8 @@ Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain)
case MHP_DelegatedApplicationDescriptorTag:
case MHP_ApplicationStorageDescriptorTag:
default:
if (!returnUnimplemetedDescriptor)
return 0;
d=new UnimplementedDescriptor();
break;
}

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: si.h 1.8 2004/02/23 17:02:33 kls Exp $
* $Id: si.h 1.9 2004/03/07 10:09:49 kls Exp $
* *
***************************************************************************/
@ -252,8 +252,11 @@ protected:
//returns a subclass of descriptor according to the data given.
//The object is allocated with new and must be delete'd.
//setData() will have been called, CheckParse() not.
//Never returns null - maybe the UnimplementedDescriptor.
static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain);
//if returnUnimplemetedDescriptor==true:
// Never returns null - maybe the UnimplementedDescriptor.
//if returnUnimplemetedDescriptor==false:
// Never returns the UnimplementedDescriptor - maybe null
static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor);
};
class Loop : public VariableLengthPart {
@ -266,6 +269,7 @@ public:
template <class T> friend class StructureLoop;
friend class DescriptorLoop;
template <class T> friend class TypeLoop;
friend class ExtendedEventDescriptors;
int i;
};
protected:
@ -311,14 +315,46 @@ public:
//returns null if no more descriptors available
Descriptor *getNext(Iterator &it);
//return the next descriptor with given tag, or 0 if not available.
//if the descriptor found is not implemented,
// an UnimplementedDescriptor will be returned if returnUnimplemetedDescriptor==true,
// 0 will be returned if returnUnimplemetedDescriptor==false
//if returnUnimplemetedDescriptor==true:
// an UnimplementedDescriptor may be returned if the next matching descriptor is unimplemented,
// 0 will be returned if and only if no matching descriptor is found.
//if returnUnimplemetedDescriptor==false:
// if 0 is returned, either no descriptor with the given tag was found,
// or descriptors were found, but the descriptor type is not implemented
//In either case, a return value of 0 indicates that no further calls to this method
//with the iterator shall be made.
Descriptor *getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor=false);
//return the next descriptor with one of the given tags, or 0 if not available.
//if returnUnimplemetedDescriptor==true:
// returns 0 if and only if no descriptor with one of the given tags was found.
// The UnimplementedDescriptor may be returned.
//if returnUnimplemetedDescriptor==false:
// if 0 is returned, either no descriptor with one of the given tags was found,
// or descriptors were found, but none of them are implemented.
// The UnimplementedDescriptor will never be returned.
//In either case, a return value of 0 indicates that no further calls to this method
//with the iterator shall be made.
Descriptor *getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor=false);
//returns the number of descriptors in this loop
int getNumberOfDescriptors();
//writes the tags of the descriptors in this loop in the array,
// which must at least have the size getNumberOfDescriptors().
//The number of descriptors, i.e. getNumberOfDescriptors(), is returned.
// You can specify the array type (Descriptor tags are 8 Bit,
// you might e.g. choose a char, short, int or DescriptorTag array)
template <typename T> int getDescriptorTags(T *tags)
{
const unsigned char *p=data.getData();
const unsigned char *end=p+getLength();
int count=0;
while (p < end) {
tags[count++]=(T)Descriptor::getDescriptorTag(p);
p+=Descriptor::getLength(p);
}
return count;
}
protected:
Descriptor *createDescriptor(int &i);
Descriptor *createDescriptor(int &i, bool returnUnimplemetedDescriptor);
DescriptorTagDomain domain;
};
@ -385,7 +421,7 @@ class String : public VariableLengthPart {
public:
//A note to the length: getLength() returns the length of the raw data.
//The text may be shorter. Its length can be obtained with one of the
//above functions and strlen.
//getText functions and strlen.
//returns text. Data is allocated with new and must be delete'd by the user.
char *getText();
@ -394,10 +430,19 @@ public:
//In most descriptors the string length is an 8-bit field,
//so the maximum there is 256.
//returns the given buffer for convenience.
char * getText(char *buffer);
//The emphasis marks 0x86 and 0x87 are still available.
char *getText(char *buffer);
//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
//length as buffer). If no shortVersion is available, shortVersion will contain
//an empty string.
//The emphasis marks 0x86 and 0x87 are still available in buffer, but not in shortVersion.
char *getText(char *buffer, char *shortVersion);
protected:
virtual void Parse() {}
void decodeText(char *buffer);
void decodeText(char *buffer, char *shortVersion);
};
} //end of namespace

27
sdt.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: sdt.c 1.7 2004/01/17 17:27:49 kls Exp $
* $Id: sdt.c 1.8 2004/03/07 10:46:08 kls Exp $
*/
#include "sdt.h"
@ -57,34 +57,17 @@ void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
//XXX TODO case 0x04: // NVOD reference service
//XXX TODO case 0x05: // NVOD time-shifted service
{
char buffer[1024];
char *p = sd->serviceName.getText(buffer);
char NameBuf[1024];
char ShortNameBuf[1024];
char *pn = NameBuf;
char *ps = ShortNameBuf;
int IsShortName = 0;
while (*p) {
if ((uchar)*p == 0x86)
IsShortName++;
else if ((uchar)*p == 0x87)
IsShortName--;
else {
*pn++ = *p;
if (IsShortName)
*ps++ = *p;
}
p++;
}
*pn = *ps = 0;
pn = NameBuf;
sd->serviceName.getText(NameBuf, ShortNameBuf);
char *pn = compactspace(NameBuf);
char *ps = compactspace(ShortNameBuf);
if (*NameBuf && *ShortNameBuf && strcmp(NameBuf, ShortNameBuf) != 0) {
ps = ShortNameBuf + strlen(ShortNameBuf);
*ps++ = ',';
strcpy(ps, NameBuf);
pn = ShortNameBuf;
}
pn = compactspace(pn);
ps = compactspace(ps);
if (channel) {
channel->SetId(sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
if (Setup.UpdateChannels >= 1)