summaryrefslogtreecommitdiff
path: root/libsi
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2004-03-14 18:00:00 +0100
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2004-03-14 18:00:00 +0100
commit9384e56566f56e77d577319a42929e708936e7c7 (patch)
tree594b86bcda612612b342c667966c678394a322fc /libsi
parent5a4eb3f1041b8a53826cebe570f9d201f3d35826 (diff)
downloadvdr-patch-lnbsharing-9384e56566f56e77d577319a42929e708936e7c7.tar.gz
vdr-patch-lnbsharing-9384e56566f56e77d577319a42929e708936e7c7.tar.bz2
Version 1.3.6vdr-1.3.6
- Completed the Finnish OSD texts (thanks to Rolf Ahrenberg). - Fixed some descriptor handling in 'libsi' (thanks to Stéphane Esté-Gracias). - Fixed handling the current menu item (thanks to Marc Hoppe). - Fixed assigning events to timers (they no longer get "stuck"). - Added log entries whenever the running status of an event changes (currently only logging the first 30 channels). - 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'). - Fixed handling VPS times at year boundaries. - Avoiding too many consecutive "ring buffer overflow" messages (which only slowed down performance even more). - Taking the Sid into account when detecting version changes in processing the PMT (thanks to Stéphane Esté-Gracias for pointing out this problem). - Completed the Russian OSD texts (thanks to Vyacheslav Dikonov). - Any newline characters in the 'description' of EPG events are now preserved to allow texts to be displayed the way the tv stations have formatted them. This was also necessary to better display itemized texts. - Fixed detecting the running status in case an empty EPG event is broadcast (thanks to Michael Pennewiß for pointing this out). - Improved performance when paging through very long menu lists. - Removed cSchedule::GetEventNumber() and cSchedule::NumEvents(). There is now cSchedule::Events() that returns the list of events directly. - Avoiding occasional bad responsiveness to user interaction caused by assigning events to timers. - Now explicitly turning on the LNB power at startup, because newer drivers don't do this any more (thanks to Oliver Endriss for pointing this out).
Diffstat (limited to 'libsi')
-rw-r--r--libsi/descriptor.c156
-rw-r--r--libsi/descriptor.h27
-rw-r--r--libsi/si.c83
-rw-r--r--libsi/si.h63
4 files changed, 283 insertions, 46 deletions
diff --git a/libsi/descriptor.c b/libsi/descriptor.c
index 0b0019f..82e2a8f 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 1.6 2004/02/22 11:11:36 kls Exp $
+ * $Id: descriptor.c 1.10 2004/03/13 15:08:12 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,84 @@ int ExtendedEventDescriptors::getTextLength() {
}
}
return ret;
-}
+}*/
-//is there a case where this function does not return the same as getTextLength?
int ExtendedEventDescriptors::getMaximumTextLength() {
+ return getMaximumTextPlainLength()+getMaximumTextItemizedLength();
+}
+
+char *ExtendedEventDescriptors::getText(const char *separation1, const char *separation2) {
+ char *text=new char[getMaximumTextLength()+strlen(separation1)+strlen(separation2)];
+ return getText(text, separation1, separation2);
+}
+
+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++) {
+ ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
+ if (!d)
+ continue;
+ d->text.getText(tempbuf);
+ len=strlen(tempbuf);
+ if (len) {
+ memcpy(buffer+index, tempbuf, len);
+ index+=len;
+ }
+ }
+
+ for (int i=0;i<length;i++) {
+ ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
+ if (!d)
+ continue;
+
+ strcpy(buffer+index, separation2); // let's have a separator between the long text and the items
+ index += strlen(separation2);
+ 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;
+}
+
+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()+1; //plus a blank
- ret+=d->itemLoop.getLength();
+ ret+=d->text.getLength();
}
return ret;
}
-char *ExtendedEventDescriptors::getText() {
- char *text=new char[getMaximumTextLength()];
- return getText(text);
+char *ExtendedEventDescriptors::getTextPlain() {
+ char *text=new char[getMaximumTextPlainLength()];
+ return getTextPlain(text);
}
-//appends the Strings of every Descriptor in the group
-char *ExtendedEventDescriptors::getText(char *buffer) {
+char *ExtendedEventDescriptors::getTextPlain(char *buffer) {
int index=0, len;
char tempbuf[256];
for (int i=0;i<length;i++) {
@@ -110,30 +166,98 @@ char *ExtendedEventDescriptors::getText(char *buffer) {
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()+strlen(separation1)+strlen(separation2)];
+ return getTextItemized(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.item.getText(tempbuf);
+ item.itemDescription.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
+ strcpy(buffer+index, separation1);
+ index += strlen(separation1);
- item.itemDescription.getText(tempbuf);
+ 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;
+ break;
+ } 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);
}
@@ -148,7 +272,7 @@ void TimeShiftedEventDescriptor::Parse() {
void ContentDescriptor::Parse() {
//this descriptor is only a header and a loop
- nibbleLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader));
+ nibbleLoop.setData(data+sizeof(descr_content), getLength()-sizeof(descr_content));
}
int ContentDescriptor::Nibble::getContentNibbleLevel1() const {
@@ -173,7 +297,7 @@ void ContentDescriptor::Nibble::Parse() {
void ParentalRatingDescriptor::Parse() {
//this descriptor is only a header and a loop
- ratingLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader));
+ ratingLoop.setData(data+sizeof(descr_parental_rating), getLength()-sizeof(descr_parental_rating));
}
int ParentalRatingDescriptor::Rating::getRating() const {
diff --git a/libsi/descriptor.h b/libsi/descriptor.h
index 17c81eb..3368b0a 100644
--- a/libsi/descriptor.h
+++ b/libsi/descriptor.h
@@ -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 {
diff --git a/libsi/si.c b/libsi/si.c
index ee64802..9ce46f0 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 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))
+ from++;
+ }
+ *to = '\0';
+}
+
+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) {
+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;
}
diff --git a/libsi/si.h b/libsi/si.h
index befff85..195830d 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 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