From 823081b59e4fe6e54b547c13e65df31504b7d418 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 7 Mar 2004 11:13:54 +0100 Subject: Fixed handling itemized texts in EPG data --- libsi/descriptor.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++----- libsi/descriptor.h | 27 +++++++--- libsi/si.c | 83 ++++++++++++++++++++++++------ libsi/si.h | 63 +++++++++++++++++++---- 4 files changed, 277 insertions(+), 43 deletions(-) (limited to 'libsi') diff --git a/libsi/descriptor.c b/libsi/descriptor.c index b552ae7c..d85a6a13 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.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;itext.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,82 @@ 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()]; + 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;itext.getText(tempbuf); + len=strlen(tempbuf); + if (len) { + memcpy(buffer+index, tempbuf, len); + index+=len; + } + } + + for (int i=0;iitemLoop.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;itext.getLength()+1; //plus a blank - ret+=d->itemLoop.getLength(); + ret+=d->text.getLength(); } return ret; } -char *ExtendedEventDescriptors::getText() { - char *text=new char[getMaximumTextLength()]; +char *ExtendedEventDescriptors::getTextPlain() { + char *text=new char[getMaximumTextPlainLength()]; return getText(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;iitemLoop.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;iitemLoop.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 (;indexitemLoop.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 indexreference_service_id); } diff --git a/libsi/descriptor.h b/libsi/descriptor.h index 17c81eb0..3368b0a9 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 ee648020..9ce46f0d 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.igetDescriptorTag()==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.igetDescriptorTag()==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 +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 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 befff85b..195830d6 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 friend class StructureLoop; friend class DescriptorLoop; template 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 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 -- cgit v1.2.3