diff --git a/src/eitd/SIevents.cpp b/src/eitd/SIevents.cpp index 04c853153..d3dcd5a79 100644 --- a/src/eitd/SIevents.cpp +++ b/src/eitd/SIevents.cpp @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -42,7 +44,9 @@ #include "SIutils.hpp" #include "SIevents.hpp" -const std::string languangeOFF = "OFF"; +#include +#include +#include struct descr_generic_header { unsigned descriptor_tag : 8; @@ -74,6 +78,71 @@ inline unsigned min(unsigned a, unsigned b) return b < a ? b : a; } +static OpenThreads::Mutex countryMutex; +static std::vector countryVector; + +unsigned int getCountryIndex(const std::string &country) +{ + unsigned int ix = 0; + OpenThreads::ScopedLock m_lock(countryMutex); + if (!countryVector.size()) { + countryVector.push_back("DEU"); // 0 + countryVector.push_back("FRA"); // 1 + countryVector.push_back("ITA"); // 2 + countryVector.push_back("ESP"); // 3 + } + for (std::vector::iterator it = countryVector.begin(); it != countryVector.end(); ++it, ++ix) + if (*it == country) + return ix; + countryVector.push_back(country); + return ix; +} + +static OpenThreads::Mutex componentMutex; +static std::vector componentVector; +static std::map componentMap; + +void SIcomponent::setComponent(const std::string &component_description) +{ + OpenThreads::ScopedLock m_lock(componentMutex); + if (!componentVector.size()) { + componentMap[""] = 0; + componentVector.push_back(""); + } + std::map::const_iterator it = componentMap.find(component_description); + if (it == componentMap.end()) { + component = componentVector.size(); + componentMap[component_description] = component; + componentVector.push_back(component_description); + } else + component = it->second; +} + +const char *SIcomponent::getComponentName() const +{ + if (component < componentVector.size()) + return componentVector[component].c_str(); + return ""; +} + +SIparentalRating::SIparentalRating(const std::string &cc, unsigned char rate) +{ + rating=rate; + countryCode=getCountryIndex(cc); +} + +void SIparentalRating::dump(void) const +{ + printf("Rating: %s %hhu (+3)\n", countryVector[countryCode].c_str(), rating); +} + +int SIparentalRating::saveXML(FILE *file) const +{ + if(fprintf(file, "\t\t\t\n", countryVector[countryCode].c_str(), rating)<0) + return 1; + return 0; +} + SIevent::SIevent(const t_original_network_id _original_network_id, const t_transport_stream_id _transport_stream_id, const t_service_id _service_id, const unsigned short _event_id) { @@ -131,16 +200,20 @@ void SIevent::parse(Event &event) times.insert(SItime(start_time, duration)); const DescriptorList &dlist = *event.getDescriptors(); for (DescriptorConstIterator dit = dlist.begin(); dit != dlist.end(); ++dit) { - uint8_t dtype = (*dit)->getTag(); - if(dtype == SHORT_EVENT_DESCRIPTOR) { + switch ((*dit)->getTag()) { + case SHORT_EVENT_DESCRIPTOR: + { const ShortEventDescriptor *d = (ShortEventDescriptor*) *dit; std::string lang = d->getIso639LanguageCode(); std::transform(lang.begin(), lang.end(), lang.begin(), tolower); int table = getCountryCodeDefaultMapping(lang); - setName(lang, stringDVBUTF8(d->getEventName(), table, tsidonid)); - setText(lang, stringDVBUTF8(d->getText(), table, tsidonid)); + unsigned int _lang = getLangIndex(lang); + setName(_lang, stringDVBUTF8(d->getEventName(), table, tsidonid)); + setText(_lang, stringDVBUTF8(d->getText(), table, tsidonid)); + break; } - else if(dtype == EXTENDED_EVENT_DESCRIPTOR) { + case EXTENDED_EVENT_DESCRIPTOR: + { const ExtendedEventDescriptor *d = (ExtendedEventDescriptor*) *dit; std::string lang = d->getIso639LanguageCode(); std::transform(lang.begin(), lang.end(), lang.begin(), tolower); @@ -154,20 +227,22 @@ void SIevent::parse(Event &event) item.append("\n"); } #endif - appendExtendedText(lang, stringDVBUTF8(d->getText(), table, tsidonid)); + appendExtendedText(getLangIndex(lang), stringDVBUTF8(d->getText(), table, tsidonid)); + break; } - else if(dtype == CONTENT_DESCRIPTOR) { + case CONTENT_DESCRIPTOR: + { const ContentDescriptor * d = (ContentDescriptor *) *dit; const ContentClassificationList *clist = d->getClassifications(); - for (ContentClassificationConstIterator cit = clist->begin(); cit != clist->end(); ++cit) { - ContentClassification * c = *cit; - char content = c->getContentNibbleLevel1() << 4 | c->getContentNibbleLevel2(); - contentClassification += content; - char user = c->getUserNibble1() << 4 | c->getUserNibble2(); - userClassification += user; - } + ssize_t off = classifications.reserve(clist->size() * 2); + for (ContentClassificationConstIterator cit = clist->begin(); cit != clist->end(); ++cit) + off = classifications.set(off, + (*cit)->getContentNibbleLevel1() << 4 | (*cit)->getContentNibbleLevel2(), + (*cit)->getUserNibble1() << 4 | (*cit)->getUserNibble2()); + break; } - else if(dtype == COMPONENT_DESCRIPTOR) { + case COMPONENT_DESCRIPTOR: + { const ComponentDescriptor *d = (ComponentDescriptor*)*dit; SIcomponent c; c.streamContent = d->getStreamContent(); @@ -176,11 +251,13 @@ void SIevent::parse(Event &event) std::string lang = d->getIso639LanguageCode(); std::transform(lang.begin(), lang.end(), lang.begin(), tolower); int table = getCountryCodeDefaultMapping(lang); - c.component = stringDVBUTF8(d->getText(), table, tsidonid); + c.setComponent(stringDVBUTF8(d->getText(), table, tsidonid)); //components.insert(c); components.push_back(c); + break; } - else if(dtype == PARENTAL_RATING_DESCRIPTOR) { + case PARENTAL_RATING_DESCRIPTOR: + { const ParentalRatingDescriptor *d = (ParentalRatingDescriptor*) *dit; const ParentalRatingList *plist = d->getParentalRatings(); for (ParentalRatingConstIterator it = plist->begin(); it != plist->end(); ++it) { @@ -188,8 +265,10 @@ void SIevent::parse(Event &event) //ratings.insert(p); ratings.push_back(p); } + break; } - else if(dtype == LINKAGE_DESCRIPTOR) { + case LINKAGE_DESCRIPTOR: + { const LinkageDescriptor * d = (LinkageDescriptor *) *dit; SIlinkage l; l.linkageType = d->getLinkageType(); @@ -199,11 +278,16 @@ void SIevent::parse(Event &event) const PrivateDataByteVector *privateData = d->getPrivateDataBytes(); l.name = convertDVBUTF8((const char*)&((*privateData)[0]), privateData->size(), 1, tsidonid); linkage_descs.insert(linkage_descs.end(), l); + break; } #if 0 // TODO ? vps was never used - else if(dtype == PDC_DESCRIPTOR) { + case PDC_DESCRIPTOR) { + break; } #endif + default: + break; + } } } @@ -257,15 +341,16 @@ void SIevent::parseShortEventDescriptor(const uint8_t *buf, unsigned maxlen) std::string language(lang); int table = getCountryCodeDefaultMapping(language); + unsigned int _language = getLangIndex(language); buf+=sizeof(struct descr_short_event_header); if(evt->event_name_length) - setName(language, convertDVBUTF8((const char*) buf, evt->event_name_length, table, tsidonid)); + setName(_language, convertDVBUTF8((const char*) buf, evt->event_name_length, table, tsidonid)); buf+=evt->event_name_length; unsigned char textlength=*((unsigned char *)buf); if(textlength > 2) - setText(language, convertDVBUTF8((const char*) (++buf), textlength, table, tsidonid)); + setText(_language, convertDVBUTF8((const char*) (++buf), textlength, table, tsidonid)); } void SIevent::parseExtendedEventDescriptor(const uint8_t *buf, unsigned maxlen) @@ -284,6 +369,7 @@ void SIevent::parseExtendedEventDescriptor(const uint8_t *buf, unsigned maxlen) std::string language(lang); int table = getCountryCodeDefaultMapping(language); + unsigned int _language = getLangIndex(language); unsigned char *items=(unsigned char *)(buf+sizeof(struct descr_extended_event_header)); while(items < (unsigned char *)(buf + sizeof(struct descr_extended_event_header) + evt->length_of_items)) { @@ -303,7 +389,7 @@ void SIevent::parseExtendedEventDescriptor(const uint8_t *buf, unsigned maxlen) items+=1+*items; } if(*items) - appendExtendedText(language, convertDVBUTF8((const char *)(items+1), min(maxlen-(items+1-buf), (*items)), table, tsidonid)); + appendExtendedText(_language, convertDVBUTF8((const char *)(items+1), min(maxlen-(items+1-buf), (*items)), table, tsidonid)); } void SIevent::parseContentDescriptor(const uint8_t *buf, unsigned maxlen) @@ -311,13 +397,8 @@ void SIevent::parseContentDescriptor(const uint8_t *buf, unsigned maxlen) struct descr_generic_header *cont=(struct descr_generic_header *)buf; if(cont->descriptor_length+sizeof(struct descr_generic_header)>maxlen) return; - - const uint8_t *classification=buf+sizeof(struct descr_generic_header); - while(classification <= buf+sizeof(struct descr_generic_header)+cont->descriptor_length-2) { - contentClassification+=std::string((const char *)classification, 1); - userClassification+=std::string((const char *)classification+1, 1); - classification+=2; - } + ssize_t off = classifications.reserve(cont->descriptor_length); + classifications.set(off, buf + sizeof(struct descr_generic_header), cont->descriptor_length); } void SIevent::parseComponentDescriptor(const uint8_t *buf, unsigned maxlen) @@ -339,6 +420,7 @@ void SIevent::parseParentalRatingDescriptor(const uint8_t *buf, unsigned maxlen) s+=4; } } + void SIevent::parseLinkageDescriptor(const uint8_t *buf, unsigned maxlen) { if(maxlen>=sizeof(struct descr_linkage_header)) { @@ -351,35 +433,31 @@ char SIevent::getFSK() const { for (SIparentalRatings::const_iterator it = ratings.begin(); it != ratings.end(); ++it) { - if (it->countryCode == "DEU") - { + if (it->countryCode == 0 /*"DEU"*/) { if ((it->rating >= 0x01) && (it->rating <= 0x0F)) return (it->rating + 3); // 0x01 to 0x0F minimum age = rating + 3 years - else - return (it->rating == 0 ? 0 : 18); // return FSK 18 for : 0x10 to 0xFF defined by the broadcaster - }else if( it->countryCode == "FRA" && it->rating == 0x10)// workaround for ITA ESP FRA fsk. - { + return (it->rating == 0 ? 0 : 18); // return FSK 18 for : 0x10 to 0xFF defined by the broadcaster + } + if( it->countryCode == 1 /*"FRA"*/ && it->rating == 0x10) { + // workaround for ITA ESP FRA fsk. return 0; - }else if(it->countryCode == "ITA" && it->rating == 1) - { + } + if(it->countryCode == 2 /*"ITA"*/ && it->rating == 1) { return 0; - }else if( it->countryCode == "ESP" ) - { + } + if( it->countryCode == 3 /*"ESP"*/ ) { if(it->rating == 0x10 || it->rating == 0x11) return 0; - else if(it->rating == 0x12) + if(it->rating == 0x12) return 18; - else - return (it->rating + 1); + return (it->rating + 1); } - } if (!ratings.empty()) { if ((ratings.begin()->rating >= 0x01) && (ratings.begin()->rating <= 0x0F)) return (ratings.begin()->rating + 3); - else - return (ratings.begin()->rating == 0 ? 0 : 18); + return (ratings.begin()->rating == 0 ? 0 : 18); } return 0x00; // 0x00 undefined @@ -388,81 +466,110 @@ char SIevent::getFSK() const std::string SIevent::getName() const { if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) { - std::map::const_iterator it = langName.begin() ; - if (it != langName.end()) return it->second; - else return(""); + if (langData.size()) + return langData.begin()->text[SILangData::langName]; + return ""; } else { std::string retval; - SIlanguage::filter(langName, 1, retval); + SIlanguage::filter(langData, SILangData::langName, 1, retval); return retval; } } void SIevent::setName(const std::string &lang, const std::string &name) +{ + setName(getLangIndex(lang), name); +} + +void SIevent::setName(unsigned int lang, const std::string &name) { std::string tmp = name; std::replace(tmp.begin(), tmp.end(), '\n', ' '); -//printf("setName: lang %s text %s\n", lang.c_str(), name.c_str()); - if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) { - langName[languangeOFF] = tmp; //name; - } else { - langName[lang] = tmp; //name; - } + + if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) + lang = 0; + + for (std::list::iterator it = langData.begin(); it != langData.end(); ++it) + if (it->lang == lang) { + it->text[SILangData::langName] = tmp; + return; + } + + SILangData ld; + ld.lang = lang; + ld.text[SILangData::langName] = tmp; + langData.push_back(ld); } std::string SIevent::getText() const { if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) { - std::map::const_iterator it = langText.begin() ; - if (it != langText.end()) return it->second; - else return(""); - } else { - std::string retval; - SIlanguage::filter(langText, 0, retval); - return retval; + if (langData.size()) + return langData.begin()->text[SILangData::langText]; + return ""; } + std::string retval; + SIlanguage::filter(langData, SILangData::langText, 0, retval); + return retval; } void SIevent::setText(const std::string &lang, const std::string &text) { -//printf("setText: lang %s text %s\n", lang.c_str(), text.c_str()); - if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) { - langText[languangeOFF] = text; - } else { - langText[lang] = text; - } + setText(getLangIndex(lang), text); +} + +void SIevent::setText(unsigned int lang, const std::string &text) +{ + if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) + lang = 0; + + for (std::list::iterator it = langData.begin(); it != langData.end(); ++it) + if (it->lang == lang) { + it->text[SILangData::langText] = text; + return; + } + + SILangData ld; + ld.lang = lang; + ld.text[SILangData::langText] = text; + langData.push_back(ld); } std::string SIevent::getExtendedText() const { if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) { - std::map::const_iterator it = langExtendedText.begin() ; - if (it != langExtendedText.end()) return it->second; - else return(""); - } else { - std::string retval; - SIlanguage::filter(langExtendedText, 0, retval); - return retval; + if (langData.size()) + return langData.begin()->text[SILangData::langExtendedText]; + return ""; } + std::string retval; + SIlanguage::filter(langData, SILangData::langExtendedText, 0, retval); + return retval; } -void SIevent::appendExtendedText(const std::string &lang, const std::string &text) +void SIevent::appendExtendedText(const std::string &lang, const std::string &text, bool append) { - if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) { - langExtendedText[languangeOFF] += text; - } else { - langExtendedText[lang] += text; - } + appendExtendedText(getLangIndex(lang), text, append); } -void SIevent::setExtendedText(const std::string &lang, const std::string &text) +void SIevent::appendExtendedText(unsigned int lang, const std::string &text, bool append) { -//printf("setExtendedText: lang %s text %s\n", lang.c_str(), text.c_str()); - if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) { - langExtendedText[languangeOFF] = text; - } else { - langExtendedText[lang] = text; - } + if (CSectionsdClient::LANGUAGE_MODE_OFF == SIlanguage::getMode()) + lang = 0; + + for (std::list::iterator it = langData.begin(); it != langData.end(); ++it) + if (it->lang == lang) { + if (append) + it->text[SILangData::langExtendedText] += text; + else + it->text[SILangData::langExtendedText] = text; + return; + } + + SILangData ld; + ld.lang = lang; + ld.text[SILangData::langExtendedText] = text; + langData.push_back(ld); } int SIevent::saveXML(FILE *file, const char *serviceName) const @@ -488,23 +595,17 @@ int SIevent::saveXML0(FILE *file) const int SIevent::saveXML2(FILE *file) const { - for (std::map::const_iterator - i = langName.begin() ; - i != langName.end() ; - ++i) { - if (i->second.length()) { - fprintf(file, "\t\t\tfirst.c_str()); - saveStringToXMLfile(file, i->second.c_str()); + for (std::list::const_iterator i = langData.begin(); i != langData.end(); ++i) { + if (i->text[SILangData::langName].length()) { + fprintf(file, "\t\t\tlang].c_str()); + saveStringToXMLfile(file, i->text[SILangData::langName].c_str()); fprintf(file, "\"/>\n"); } } - for (std::map::const_iterator - i = langText.begin() ; - i != langText.end() ; - ++i) { - if (i->second.length()) { - fprintf(file, "\t\t\tfirst.c_str()); - saveStringToXMLfile(file, i->second.c_str()); + for (std::list::const_iterator i = langData.begin(); i != langData.end(); ++i) { + if (i->text[SILangData::langText].length()) { + fprintf(file, "\t\t\tlang].c_str()); + saveStringToXMLfile(file, i->text[SILangData::langText].c_str()); fprintf(file, "\"/>\n"); } } @@ -520,17 +621,16 @@ int SIevent::saveXML2(FILE *file) const fprintf(file, "\"/>\n"); } #endif - for (std::map::const_iterator - i = langExtendedText.begin() ; - i != langExtendedText.end() ; - ++i) { - if (i->second.length()) { - fprintf(file, "\t\t\tfirst.c_str()); - saveStringToXMLfile(file, i->second.c_str()); + for (std::list::const_iterator i = langData.begin(); i != langData.end(); ++i) { + if (i->text[SILangData::langExtendedText].length()) { + fprintf(file, "\t\t\tlang].c_str()); + saveStringToXMLfile(file, i->text[SILangData::langExtendedText].c_str()); fprintf(file, "\"/>\n"); } } for_each(times.begin(), times.end(), saveSItimeXML(file)); + std::string contentClassification, userClassification; + classifications.get(contentClassification, userClassification); for(unsigned i=0; i::const_iterator it = langName.begin() ; - it != langName.end() ; ++it) - printf("Name (%s): %s\n", it->first.c_str(), it->second.c_str()); - for (std::map::const_iterator it = langText.begin() ; - it != langText.end() ; ++it) - printf("Text (%s): %s\n", it->first.c_str(), it->second.c_str()); - for (std::map::const_iterator it = langExtendedText.begin() ; - it != langExtendedText.end() ; ++it) - printf("Extended-Text (%s): %s\n", it->first.c_str(), it->second.c_str()); + for (std::list::const_iterator it = langData.begin(); it != langData.end(); ++it) { + printf("Name (%s): %s\n", langIndex[it->lang].c_str(), it->text[SILangData::langName].c_str()); + printf("Text (%s): %s\n", langIndex[it->lang].c_str(), it->text[SILangData::langText].c_str()); + printf("Extended-Text (%s): %s\n", langIndex[it->lang].c_str(), it->text[SILangData::langExtendedText].c_str()); + } + std::string contentClassification, userClassification; + classifications.get(contentClassification, userClassification); if(contentClassification.length()) { printf("Content classification:"); for(unsigned i=0; i::const_iterator it = langName.begin() ; + for (std::list >::const_iterator it = langName.begin() ; it != langName.end() ; ++it) printf("Name (%s): %s\n", it->first.c_str(), it->second.c_str()); - for (std::map::const_iterator it = langText.begin() ; + for (std::list >::const_iterator it = langText.begin() ; it != langText.end() ; ++it) printf("Text (%s): %s\n", it->first.c_str(), it->second.c_str()); - for (std::map::const_iterator it = langExtendedText.begin() ; + for (std::list >::const_iterator it = langExtendedText.begin() ; it != langExtendedText.end() ; ++it) printf("Extended-Text (%s): %s\n", it->first.c_str(), it->second.c_str()); diff --git a/src/eitd/SIevents.hpp b/src/eitd/SIevents.hpp index c1af74493..a8a445b3a 100644 --- a/src/eitd/SIevents.hpp +++ b/src/eitd/SIevents.hpp @@ -23,7 +23,7 @@ #define SIEVENTS_HPP #include -#include +#include #include #include #include @@ -31,6 +31,7 @@ #include #include #include "edvbstring.h" +#include "SIlanguage.hpp" //#define USE_ITEM_DESCRIPTION @@ -123,14 +124,14 @@ public: } void dump(void) const { - printf("Linakge Type: 0x%02hhx\n", linkageType); + printf("Linkage Type: 0x%02hhx\n", linkageType); if (name.length()) printf("Name: %s\n", name.c_str()); printf("Transport Stream Id: 0x%04hhx\n", transportStreamId); printf("Original Network Id: 0x%04hhx\n", originalNetworkId); printf("Service Id: 0x%04hhx\n", serviceId); } - + int saveXML(FILE *file) const { fprintf(file, "\t\t\t class SIcomponent { public: - std::string component; + unsigned int component; unsigned char componentType; unsigned char componentTag; unsigned char streamContent; SIcomponent(void) { + component = 0; streamContent=0; componentType=0; componentTag=0; } SIcomponent(const struct descr_component_header *comp) { + component = 0; streamContent=comp->stream_content; componentType=comp->component_type; componentTag=comp->component_tag; if(comp->descriptor_length>sizeof(struct descr_component_header)-2) - component=convertDVBUTF8(((const char *)comp)+sizeof(struct descr_component_header), - comp->descriptor_length-(sizeof(struct descr_component_header)-2), 0, 0); + setComponent(convertDVBUTF8(((const char *)comp) + sizeof(struct descr_component_header), + comp->descriptor_length-(sizeof(struct descr_component_header)-2), 0, 0)); } + void setComponent(const std::string &component_description); + const char *getComponentName() const; + void dump(void) const { - if(component.length()) - printf("Component: %s\n", component.c_str()); + const char *comp = getComponentName(); + if(*comp) + printf("Component: %s\n", comp); printf("Stream Content: 0x%02hhx\n", streamContent); printf("Component type: 0x%02hhx\n", componentType); printf("Component tag: 0x%02hhx\n", componentTag); } int saveXML(FILE *file) const { fprintf(file, "\t\t\t\n"); return 0; } @@ -247,26 +254,15 @@ struct saveSIcomponentXML : public std::unary_function class SIparentalRating { public: - std::string countryCode; - unsigned char rating; // Bei 1-16 -> Minumim Alter = rating +3 + unsigned int countryCode; + unsigned char rating; // Bei 1-16 -> Minimales Alter = rating +3 - SIparentalRating(const std::string &cc, unsigned char rate) { - rating=rate; - countryCode=cc; - } + SIparentalRating(const std::string &cc, unsigned char rate); // Der Operator zum sortieren bool operator < (const SIparentalRating& c) const { return countryCode < c.countryCode; } - void dump(void) const { - printf("Rating: %s %hhu (+3)\n", countryCode.c_str(), rating); - } - int saveXML(FILE *file) const { - if(fprintf(file, "\t\t\t\n", countryCode.c_str(), rating)<0) - return 1; - return 0; - } bool operator==(const SIparentalRating& p) const { return (rating == p.rating) && (countryCode == p.countryCode); @@ -275,6 +271,8 @@ class SIparentalRating return (rating != p.rating) || (countryCode != p.countryCode); } + void dump(void) const; + int saveXML(FILE *file) const; }; //typedef std::set > SIparentalRatings; typedef std::vector SIparentalRatings; @@ -344,9 +342,7 @@ struct saveSItimeXML : public std::unary_function class SIevent { private: - std::map langName; - std::map langText; - std::map langExtendedText; + std::list langData; int running; void parseShortEventDescriptor(const uint8_t *buf, unsigned maxlen); @@ -378,8 +374,112 @@ class SIevent std::string itemDescription; // Aus dem Extended Descriptor std::string item; // Aus dem Extended Descriptor #endif - std::string contentClassification; // Aus dem Content Descriptor, als String, da mehrere vorkommen koennen - std::string userClassification; // Aus dem Content Descriptor, als String, da mehrere vorkommen koennen + struct SIeventClassifications + { + uint8_t *data; + unsigned int size; + + SIeventClassifications& operator = (const SIeventClassifications& c) + { + if (this != &c) { + if (data) + free(data); + if (c.data) { + data = (uint8_t *) malloc(c.size); + memcpy(data, c.data, c.size); + } else + data = NULL; + size = c.size; + } + return *this; + } + + SIeventClassifications(const SIeventClassifications& c) + { + if (this != &c) { + if (c.data) { + data = (uint8_t *) malloc(c.size); + memcpy(data, c.data, c.size); + } else + data = NULL; + size = c.size; + } + } + + bool operator==(const SIeventClassifications& c) const + { + if (!data && !c.data) + return true; + if (!(data && c.data)) + return false; + if (size != c.size) + return false; + return !memcmp(data, c.data, size); + } + + bool operator!=(const SIeventClassifications& c) const + { + return *this == c; + } + + SIeventClassifications() + { + data = NULL; + size = 0; + } + + ~SIeventClassifications() + { + if (data) free(data); + } + + void get(std::string &contentClassifications, std::string &userClassifications) const + { + contentClassifications.clear(); + userClassifications.clear(); + uint8_t *d = data; + unsigned int z = size & ~1; + for (unsigned int i = 0; i < z; i += 2) { + contentClassifications.append(1, (char)(*d++)); + userClassifications.append(1, (char)(*d++)); + } + } + + ssize_t reserve(unsigned int r) + { + size_t off = size; + + if (off) { + uint8_t * _data = (uint8_t *) realloc(data, size + r); + if (!_data) + return -1; + data = _data; + } else + data = (uint8_t *) malloc(r); + size += r; + return off; + } + + ssize_t set(ssize_t off, uint8_t content, uint8_t user) + { + if (off < -1 || off + 2 >= (ssize_t) size) + return -1; + data[off++] = content; + data[off++] = user; + return off; + } + + ssize_t set(ssize_t off, const uint8_t *_data, size_t _size) + { + if (off < -1 || off + _size >= size) + return -1; + memcpy (data + off, _data, _size); + size += _size; + return size; + } + }; + + SIeventClassifications classifications; SIevent(const t_original_network_id, const t_transport_stream_id, const t_service_id, const unsigned short); SIevent(void) { @@ -400,15 +500,23 @@ class SIevent // Name aus dem Short-Event-Descriptor std::string getName() const; void setName(const std::string &lang, const std::string &name); + void setName(unsigned int lang, const std::string &name); // Text aus dem Short-Event-Descriptor std::string getText() const; void setText(const std::string &lang, const std::string &text); + void setText(unsigned int lang, const std::string &text); // Aus dem Extended Descriptor std::string getExtendedText() const; - void appendExtendedText(const std::string &lang, const std::string &text); - void setExtendedText(const std::string &lang, const std::string &text); + void appendExtendedText(const std::string &lang, const std::string &text, bool append = true); + void appendExtendedText(unsigned int lang, const std::string &text, bool append = true); + void setExtendedText(const std::string &lang, const std::string &text) { + appendExtendedText(lang, text, false); + } + void setExtendedText(unsigned int lang, const std::string &text) { + appendExtendedText(lang, text, false); + } t_channel_id get_channel_id(void) const { return CREATE_CHANNEL_ID(service_id, original_network_id, transport_stream_id); diff --git a/src/eitd/SIlanguage.cpp b/src/eitd/SIlanguage.cpp index 6229cf45f..6521afe1b 100644 --- a/src/eitd/SIlanguage.cpp +++ b/src/eitd/SIlanguage.cpp @@ -32,12 +32,35 @@ #include #include +#include +#include +#include + #include #include "SIlanguage.hpp" -std::vector SIlanguage::languages; -pthread_mutex_t SIlanguage::languages_lock = PTHREAD_MUTEX_INITIALIZER; +static OpenThreads::Mutex languages_lock; +static std::vector languages; + +static OpenThreads::Mutex langIndexMutex; +std::vector langIndex; + +static const std::string languageOFF = "OFF"; + +unsigned int getLangIndex(const std::string &lang) +{ + unsigned int ix = 0; + OpenThreads::ScopedLock m_lock(langIndexMutex); + if (!langIndex.size()) + langIndex.push_back(languageOFF); + for (std::vector::iterator it = langIndex.begin(); it != langIndex.end(); ++it, ++ix) + if (*it == lang) + return ix; + langIndex.push_back(lang); + return ix; +} + /* ALL = Show all available languages @@ -49,22 +72,26 @@ ALL_ALL = Show all wanted languages if possible. If not found show all available //CSectionsdClient::SIlanguageMode_t SIlanguage::mode = CSectionsdClient::ALL; CSectionsdClient::SIlanguageMode_t SIlanguage::mode = CSectionsdClient::FIRST_ALL; -void SIlanguage::filter(const std::map& s, int max, std::string& retval) +void SIlanguage::filter(const std::list& s, SILangData::SILangDataIndex textIndex, int max, std::string& retval) { - pthread_mutex_lock(&languages_lock); // languages cannot get iterated through // if another thread is updating it simultaneously int count = max; + OpenThreads::ScopedLock m_lock(languages_lock); if (mode != CSectionsdClient::ALL) { for (std::vector::const_iterator it = languages.begin() ; it != languages.end() ; ++it) { - std::map::const_iterator text; - if ((text = s.find(*it)) != s.end()) { + std::list::const_iterator text; + unsigned int lang = getLangIndex(*it); + for (text = s.begin(); text != s.end() && text->lang != lang; ++text); + if (text != s.end()) { + if (text->text[textIndex].empty()) + continue; if (count != max) { retval.append(" \n"); } - retval.append(text->second); + retval.append(text->text[textIndex]); if (--count == 0) break; if (mode == CSectionsdClient::FIRST_FIRST || mode == CSectionsdClient::FIRST_ALL) { @@ -77,12 +104,14 @@ void SIlanguage::filter(const std::map& s, int max, st if (retval.length() == 0) { // return all available languages if (s.begin() != s.end()) { - for (std::map::const_iterator it = s.begin() ; + for (std::list::const_iterator it = s.begin() ; it != s.end() ; ++it) { + if (it->text[textIndex].empty()) + continue; if (it != s.begin()) { retval.append(" \n"); } - retval.append(it->second); + retval.append(it->text[textIndex]); if (--max == 0) break; if (mode == CSectionsdClient::FIRST_FIRST || mode == CSectionsdClient::ALL_FIRST) { @@ -91,13 +120,12 @@ void SIlanguage::filter(const std::map& s, int max, st } } } - pthread_mutex_unlock(&languages_lock); } bool SIlanguage::loadLanguages() { - pthread_mutex_lock(&languages_lock); + OpenThreads::ScopedLock m_lock(languages_lock); std::ifstream file(LANGUAGEFILE); std::string word; CSectionsdClient::SIlanguageMode_t tmpMode = CSectionsdClient::FIRST_ALL; @@ -125,20 +153,18 @@ bool SIlanguage::loadLanguages() if (tmpLang.empty()) tmpLang.push_back("OFF"); languages = tmpLang; mode = tmpMode; - pthread_mutex_unlock(&languages_lock); return true; error: tmpLang.push_back("OFF"); languages = tmpLang; mode = tmpMode; - pthread_mutex_unlock(&languages_lock); return false; } bool SIlanguage::saveLanguages() { - pthread_mutex_lock(&languages_lock); + OpenThreads::ScopedLock m_lock(languages_lock); std::ofstream file(LANGUAGEFILE); switch(mode) { case CSectionsdClient::ALL: @@ -171,26 +197,22 @@ bool SIlanguage::saveLanguages() file.close(); if (file.fail()) goto error; - pthread_mutex_unlock(&languages_lock); return true; error: - pthread_mutex_unlock(&languages_lock); return false; } void SIlanguage::setLanguages(const std::vector& newLanguages) { - pthread_mutex_lock(&languages_lock); + OpenThreads::ScopedLock m_lock(languages_lock); languages = newLanguages; - pthread_mutex_unlock(&languages_lock); } std::vector SIlanguage::getLanguages() { - pthread_mutex_lock(&languages_lock); + OpenThreads::ScopedLock m_lock(languages_lock); std::vector retval(languages); // Store it before unlock - pthread_mutex_unlock(&languages_lock); return retval; } diff --git a/src/eitd/SIlanguage.hpp b/src/eitd/SIlanguage.hpp index 0c3c057bd..0155d7f62 100644 --- a/src/eitd/SIlanguage.hpp +++ b/src/eitd/SIlanguage.hpp @@ -25,15 +25,22 @@ #include #include -#include +#include #include #define LANGUAGEFILE CONFIGDIR "/epglanguages.conf" +class SILangData { +public: + enum SILangDataIndex { langName = 0, langText, langExtendedText, langMax }; + unsigned int lang; + std::string text[langMax]; +}; + class SIlanguage { public: - static void filter(const std::map& s, int max, std::string& retval); + static void filter(const std::list& s, SILangData::SILangDataIndex textIndex, int max, std::string& retval); static bool loadLanguages(); static bool saveLanguages(); static void setLanguages(const std::vector& newLanguages); @@ -44,9 +51,9 @@ public: private: SIlanguage(); ~SIlanguage(); - static std::vector languages; - static pthread_mutex_t languages_lock; static CSectionsdClient::SIlanguageMode_t mode; }; +extern std::vector langIndex; +unsigned int getLangIndex(const std::string &lang); #endif diff --git a/src/eitd/sectionsd.cpp b/src/eitd/sectionsd.cpp index c229e77e5..fe7c7106d 100644 --- a/src/eitd/sectionsd.cpp +++ b/src/eitd/sectionsd.cpp @@ -344,8 +344,7 @@ xprintf("addEvent: ch %012" PRIx64 " running %d (%s) got_CN %d\n", evt.get_chann already_exists = false; if ((already_exists) && (SIlanguage::getMode() == CSectionsdClient::LANGUAGE_MODE_OFF)) { - si->second->contentClassification = evt.contentClassification; - si->second->userClassification = evt.userClassification; + si->second->classifications = evt.classifications; #ifdef USE_ITEM_DESCRIPTION si->second->itemDescription = evt.itemDescription; si->second->item = evt.item; @@ -353,11 +352,11 @@ xprintf("addEvent: ch %012" PRIx64 " running %d (%s) got_CN %d\n", evt.get_chann //si->second->vps = evt.vps; if ((evt.getExtendedText().length() > 0) && !evt.times.empty() && (evt.times.begin()->startzeit < zeit + secondsExtendedTextCache)) - si->second->setExtendedText("OFF",evt.getExtendedText().c_str()); + si->second->setExtendedText(0 /*"OFF"*/,evt.getExtendedText()); if (evt.getText().length() > 0) - si->second->setText("OFF",evt.getText().c_str()); + si->second->setText(0 /*"OFF"*/,evt.getText()); if (evt.getName().length() > 0) - si->second->setName("OFF",evt.getName().c_str()); + si->second->setName(0 /*"OFF"*/,evt.getName()); } else { @@ -375,7 +374,7 @@ xprintf("addEvent: ch %012" PRIx64 " running %d (%s) got_CN %d\n", evt.get_chann //Strip ExtendedDescription if too far in the future if ((e->times.begin()->startzeit > zeit + secondsExtendedTextCache) && (SIlanguage::getMode() == CSectionsdClient::LANGUAGE_MODE_OFF) && (zeit != 0)) - e->setExtendedText("OFF",""); + e->setExtendedText(0 /*"OFF"*/,""); /* * this is test code, so indentation is deliberately wrong :-) @@ -2601,8 +2600,7 @@ bool CEitManager::getEPGid(const event_id_t epgID, const time_t startzeit, CEPGD epgdata->info1 = evt.getText(); epgdata->info2 = evt.getExtendedText(); /* FIXME printf("itemDescription: %s\n", evt.itemDescription.c_str()); */ - epgdata->contentClassification = std::string(evt.contentClassification.data(), evt.contentClassification.length()); - epgdata->userClassification = std::string(evt.userClassification.data(), evt.userClassification.length()); + evt.classifications.get(epgdata->contentClassification, epgdata->userClassification); epgdata->fsk = evt.getFSK(); epgdata->table_id = evt.table_id; @@ -2663,8 +2661,7 @@ bool CEitManager::getActualEPGServiceKey(const t_channel_id channel_id, CEPGData epgdata->info1 = evt.getText(); epgdata->info2 = evt.getExtendedText(); /* FIXME printf("itemDescription: %s\n", evt.itemDescription.c_str());*/ - epgdata->contentClassification = std::string(evt.contentClassification.data(), evt.contentClassification.length()); - epgdata->userClassification = std::string(evt.userClassification.data(), evt.userClassification.length()); + evt.classifications.get(epgdata->contentClassification, epgdata->userClassification); epgdata->fsk = evt.getFSK(); epgdata->table_id = evt.table_id; @@ -2765,7 +2762,7 @@ bool CEitManager::getComponentTagsUniqueKey(const event_id_t uniqueKey, CSection ret = true; for (SIcomponents::iterator cmp = eFirst->second->components.begin(); cmp != eFirst->second->components.end(); ++cmp) { - response.component = cmp->component; + response.component = cmp->getComponentName(); response.componentType = cmp->componentType; response.componentTag = cmp->componentTag; response.streamContent = cmp->streamContent; diff --git a/src/eitd/xmlutil.cpp b/src/eitd/xmlutil.cpp index ed5fad71e..1baf735ba 100644 --- a/src/eitd/xmlutil.cpp +++ b/src/eitd/xmlutil.cpp @@ -40,6 +40,7 @@ #include "xmlutil.h" #include "eitd.h" #include "debug.h" +#include void addEvent(const SIevent &evt, const time_t zeit, bool cn = false); extern MySIeventsOrderServiceUniqueKeyFirstStartTimeEventUniqueKey mySIeventsOrderServiceUniqueKeyFirstStartTimeEventUniqueKey; @@ -270,12 +271,12 @@ void deleteOldfileEvents(char *epgdir) void *insertEventsfromFile(void * data) { + set_threadname(__func__); reader_ready=false; xmlDocPtr event_parser = NULL; xmlNodePtr eventfile = NULL; xmlNodePtr service = NULL; xmlNodePtr event = NULL; - xmlNodePtr node = NULL; t_original_network_id onid = 0; t_transport_stream_id tsid = 0; t_service_id sid = 0; @@ -316,86 +317,121 @@ void *insertEventsfromFile(void * data) event = service->xmlChildrenNode; while (event) { - SIevent e(onid,tsid,sid,xmlGetNumericAttribute(event, "id", 16)); uint8_t tid = xmlGetNumericAttribute(event, "tid", 16); + std::string contentClassification, userClassification; if(tid) e.table_id = tid; e.table_id |= 0x80; /* make sure on-air data has a lower table_id */ - node = event->xmlChildrenNode; + xmlNodePtr node; - while (xmlGetNextOccurence(node, "name") != NULL) { - e.setName( std::string(ZapitTools::UTF8_to_Latin1(xmlGetAttribute(node, "lang"))), - std::string(xmlGetAttribute(node, "string"))); + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "name"))) { + char *s = xmlGetAttribute(node, "string"); + if (s) + e.setName(ZapitTools::UTF8_to_Latin1(xmlGetAttribute(node, "lang")), s); node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "text") != NULL) { - e.setText( std::string(ZapitTools::UTF8_to_Latin1(xmlGetAttribute(node, "lang"))), - std::string(xmlGetAttribute(node, "string"))); + + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "text"))) { + char *s = xmlGetAttribute(node, "string"); + if (s) + e.setText(ZapitTools::UTF8_to_Latin1(xmlGetAttribute(node, "lang")), s); node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "item") != NULL) { + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "item"))) { #ifdef USE_ITEM_DESCRIPTION - e.item = std::string(xmlGetAttribute(node, "string")); + char *s = xmlGetAttribute(node, "string"); + if (s) + e.item = s; #endif node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "item_description") != NULL) { + + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "item_description"))) { #ifdef USE_ITEM_DESCRIPTION - e.itemDescription = std::string(xmlGetAttribute(node, "string")); + char *s = xmlGetAttribute(node, "string"); + if (s) + e.itemDescription = s; #endif node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "extended_text") != NULL) { - e.appendExtendedText( std::string(ZapitTools::UTF8_to_Latin1(xmlGetAttribute(node, "lang"))), - std::string(xmlGetAttribute(node, "string"))); + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "extended_text"))) { + char *l = xmlGetAttribute(node, "lang"); + char *s = xmlGetAttribute(node, "string"); + if (l && s) + e.appendExtendedText(ZapitTools::UTF8_to_Latin1(l), s); node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "time") != NULL) { + + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "time"))) { e.times.insert(SItime(xmlGetNumericAttribute(node, "start_time", 10), xmlGetNumericAttribute(node, "duration", 10))); node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "content") != NULL) { + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "content"))) { char cl = xmlGetNumericAttribute(node, "class", 16); - e.contentClassification += cl; + contentClassification += cl; cl = xmlGetNumericAttribute(node, "user", 16); - e.userClassification += cl; + userClassification += cl; node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "component") != NULL) { + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "component"))) { SIcomponent c; c.streamContent = xmlGetNumericAttribute(node, "stream_content", 16); c.componentType = xmlGetNumericAttribute(node, "type", 16); c.componentTag = xmlGetNumericAttribute(node, "tag", 16); - c.component = std::string(xmlGetAttribute(node, "text")); + char *s = xmlGetAttribute(node, "text"); + if (s) + c.setComponent(s); //e.components.insert(c); e.components.push_back(c); node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "parental_rating") != NULL) { + + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "parental_rating"))) { + char *s = xmlGetAttribute(node, "country"); + if (s) #if 0 - e.ratings.insert(SIparentalRating(std::string(ZapitTools::UTF8_to_Latin1(xmlGetAttribute(node, "country"))), + e.ratings.insert(SIparentalRating(ZapitTools::UTF8_to_Latin1(s), (unsigned char) xmlGetNumericAttribute(node, "rating", 10))); #endif - e.ratings.push_back(SIparentalRating(std::string(ZapitTools::UTF8_to_Latin1(xmlGetAttribute(node, "country"))), + e.ratings.push_back(SIparentalRating(ZapitTools::UTF8_to_Latin1(s), (unsigned char) xmlGetNumericAttribute(node, "rating", 10))); node = node->xmlNextNode; } - while (xmlGetNextOccurence(node, "linkage") != NULL) { + + node = event->xmlChildrenNode; + while ((node = xmlGetNextOccurence(node, "linkage"))) { SIlinkage l; l.linkageType = xmlGetNumericAttribute(node, "type", 16); l.transportStreamId = xmlGetNumericAttribute(node, "transport_stream_id", 16); l.originalNetworkId = xmlGetNumericAttribute(node, "original_network_id", 16); l.serviceId = xmlGetNumericAttribute(node, "service_id", 16); - l.name = std::string(xmlGetAttribute(node, "linkage_descriptor")); + char *s = xmlGetAttribute(node, "linkage_descriptor"); + if (s) + l.name = s; e.linkage_descs.insert(e.linkage_descs.end(), l); - node = node->xmlNextNode; } + + if (contentClassification.size()) { + ssize_t off = e.classifications.reserve(2 * contentClassification.size()); + if (off > -1) + for (unsigned i = 0; i < contentClassification.size(); i++) + off = e.classifications.set(off, contentClassification.at(i), userClassification.at(i)); + } addEvent(e, 0); ev_count++; @@ -411,7 +447,7 @@ void *insertEventsfromFile(void * data) xmlFreeDoc(index_parser); printdate_ms(stdout); - printf("[sectionsd] Reading Information finished after %ld miliseconds (%d events)\n", + printf("[sectionsd] Reading Information finished after %ld milliseconds (%d events)\n", time_monotonic_ms()-now, ev_count); reader_ready = true;