const char *I18nNormalizeLanguageCode(const char *Code) { for (int i = 0; i < 3; i++) { if (Code[i]) { // ETSI EN 300 468 defines language codes as consisting of three letters // according to ISO 639-2. This means that they are supposed to always consist // of exactly three letters in the range a-z - no digits, UTF-8 or other // funny characters. However, some broadcasters apparently don't have a // copy of the DVB standard (or they do, but are perhaps unable to read it), // so they put all sorts of non-standard stuff into the language codes, // like nonsense as "2ch" or "A 1" (yes, they even go as far as using // blanks!). Such things should go into the description of the EPG event's // ComponentDescriptor. // So, as a workaround for this broadcaster stupidity, let's ignore // language codes with unprintable characters... if (!isprint(Code[i])) { //dsyslog("invalid language code: '%s'", Code); return "???"; } // ...and replace blanks with underlines (ok, this breaks the 'const' // of the Code parameter - but hey, it's them who started this): if (Code[i] == ' ') *((char *)&Code[i]) = '_'; } else break; } int n = I18nLanguageIndex(Code); return n >= 0 ? I18nLanguageCode(n) : Code; }
bool I18nIsPreferredLanguage(int *PreferredLanguages, const char *LanguageCode, int &OldPreference, int *Position) { int pos = 1; bool found = false; while (LanguageCode) { int LanguageIndex = I18nLanguageIndex(LanguageCode); for (int i = 0; i < LanguageCodes.Size(); i++) { if (PreferredLanguages[i] < 0) break; // the language is not a preferred one if (PreferredLanguages[i] == LanguageIndex) { if (OldPreference < 0 || i < OldPreference) { OldPreference = i; if (Position) *Position = pos; found = true; break; } } } if ((LanguageCode = strchr(LanguageCode, '+')) != NULL) { LanguageCode++; pos++; } else if (pos == 1 && Position) *Position = 0; } if (OldPreference < 0) { OldPreference = LanguageCodes.Size(); // higher than the maximum possible value return true; // if we don't find a preferred one, we take the first one } return found; }
bool cSetup::ParseLanguages(const char *Value, int *Values) { int n = 0; while (Value && *Value && n < I18nLanguages()->Size()) { char buffer[4]; strn0cpy(buffer, Value, sizeof(buffer)); int i = I18nLanguageIndex(buffer); if (i >= 0) Values[n++] = i; if ((Value = strchr(Value, ' ')) != NULL) Value++; } Values[n] = -1; return true; }
bool cTheme::Load(const char *FileName, bool OnlyDescriptions) { if (!FileNameOk(FileName, true)) return false; bool result = false; if (!OnlyDescriptions) isyslog("loading %s", FileName); FILE *f = fopen(FileName, "r"); if (f) { int line = 0; result = true; char *s; const char *error = NULL; cReadLine ReadLine; while ((s = ReadLine.Read(f)) != NULL) { line++; char *p = strchr(s, '#'); if (p) *p = 0; s = stripspace(skipspace(s)); if (!isempty(s)) { char *n = s; char *v = strchr(s, '='); if (v) { *v++ = 0; n = stripspace(skipspace(n)); v = stripspace(skipspace(v)); if (strstr(n, "Description") == n) { int lang = 0; char *l = strchr(n, '.'); if (l) lang = I18nLanguageIndex(++l); if (lang >= 0) { free(descriptions[lang]); descriptions[lang] = strdup(v); } else error = "invalid language code"; } else if (!OnlyDescriptions) { for (int i = 0; i < MaxThemeColors; i++) { if (colorNames[i]) { if (strcmp(n, colorNames[i]) == 0) { char *p = NULL; errno = 0; tColor c = strtoul(v, &p, 16); if (!errno && !*p) colorValues[i] = c; else error = "invalid color value"; break; } } else { error = "unknown color name"; break; } } } } else error = "missing value"; } if (error) { result = false; break; } } if (!result) esyslog("ERROR: error in %s, line %d%s%s", FileName, line, error ? ": " : "", error ? error : ""); fclose(f); } else LOG_ERROR_STR(FileName); return result; }
MsgPacket* ChannelController::processGetChannels(MsgPacket* request) { ChannelCache& channelCache = ChannelCache::instance(); isyslog("Fetching channels ..."); int type = request->get_U32(); isyslog("Type: %s", type == 0 ? "MPEG2/H.264 channels" : type == 1 ? "radio channels" : type == 2 ? "H.264 channels" : "UNDEFINED" ); // // PROTOCOL 7 - CLIENT MUST SEND THIS // const char* language = request->get_String(); // do we want fta channels ? m_wantFta = request->get_U32(); isyslog("Free To Air channels: %s", m_wantFta ? "Yes" : "No"); // display only channels with native language audio ? m_filterLanguage = request->get_U32(); isyslog("Only native language: %s", m_filterLanguage ? "Yes" : "No"); // read caids m_caids.clear(); uint32_t count = request->get_U32(); isyslog("Enabled CaIDs: "); // sanity check (maximum of 20 caids) if(count < 20) { for(uint32_t i = 0; i < count; i++) { int caid = request->get_U32(); m_caids.push_back(caid); isyslog("%04X", caid); } } m_languageIndex = I18nLanguageIndex(language); m_channelCount = channelCount(); MsgPacket* response = createResponse(request); std::string groupName; LOCK_CHANNELS_READ; for(const cChannel* channel = Channels->First(); channel; channel = Channels->Next(channel)) { if(channel->GroupSep()) { groupName = m_toUtf8.convert(channel->Name()); continue; } // skip disabled channels if filtering is enabled if(!channelCache.isEnabled(channel)) { continue; } if(!isChannelWanted(channel, type)) { continue; } addChannelToPacket(channel, response, groupName.c_str()); } isyslog("client got %i channels", m_channelCount); return response; }
bool ChannelController::isChannelWanted(const cChannel* channel, int type) { // dismiss invalid channels if(channel == NULL) { return false; } // radio if((type == 1) && !isRadio(channel)) { return false; } // (U)HD channels if((type == 2) && (channel->Vtype() != 27 && channel->Vtype() != 36)) { return false; } // skip channels witout SID if(channel->Sid() == 0) { return false; } if(strcmp(channel->Name(), ".") == 0) { return false; } // check language if(m_filterLanguage && m_languageIndex != -1) { bool bLanguageFound = false; const char* lang = NULL; // check MP2 languages for(int i = 0; i < MAXAPIDS; i++) { lang = channel->Alang(i); if(lang == NULL) { break; } if(m_languageIndex == I18nLanguageIndex(lang)) { bLanguageFound = true; break; } } // check other digital languages for(int i = 0; i < MAXDPIDS; i++) { lang = channel->Dlang(i); if(lang == NULL) { break; } if(m_languageIndex == I18nLanguageIndex(lang)) { bLanguageFound = true; break; } } if(!bLanguageFound) { return false; } } // user selection for FTA channels if(channel->Ca(0) == 0) { return m_wantFta; } // we want all encrypted channels if there isn't any CaID filter if(m_caids.size() == 0) { return true; } // check if we have a matching CaID for(std::list<int>::iterator i = m_caids.begin(); i != m_caids.end(); i++) { for(int j = 0; j < MAXCAIDS; j++) { if(channel->Ca(j) == 0) { break; } if(channel->Ca(j) == *i) { return true; } } } return false; }
void cLiveStreamer::reorderStreams(int lang, cStreamInfo::Type type) { std::map<uint32_t, cTSDemuxer*> weight; // compute weights int i = 0; for (std::list<cTSDemuxer*>::iterator idx = m_Demuxers.begin(); idx != m_Demuxers.end(); idx++, i++) { cTSDemuxer* stream = (*idx); if (stream == NULL) continue; // 32bit weight: // V0000000ASLTXXXXPPPPPPPPPPPPPPPP // // VIDEO (V): 0x80000000 // AUDIO (A): 0x00800000 // SUBTITLE (S): 0x00400000 // LANGUAGE (L): 0x00200000 // STREAMTYPE (T): 0x00100000 (only audio) // AUDIOTYPE (X): 0x000F0000 (only audio) // PID (P): 0x0000FFFF #define VIDEO_MASK 0x80000000 #define AUDIO_MASK 0x00800000 #define SUBTITLE_MASK 0x00400000 #define LANGUAGE_MASK 0x00200000 #define STREAMTYPE_MASK 0x00100000 #define AUDIOTYPE_MASK 0x000F0000 #define PID_MASK 0x0000FFFF // last resort ordering, the PID uint32_t w = 0xFFFF - (stream->GetPID() & PID_MASK); // stream type weights switch(stream->GetContent()) { case cStreamInfo::scVIDEO: w |= VIDEO_MASK; break; case cStreamInfo::scAUDIO: w |= AUDIO_MASK; // weight of audio stream type w |= (stream->GetType() == type) ? STREAMTYPE_MASK : 0; // weight of audio type w |= ((4 - stream->GetAudioType()) << 16) & AUDIOTYPE_MASK; break; case cStreamInfo::scSUBTITLE: w |= SUBTITLE_MASK; break; default: break; } // weight of language int streamLangIndex = I18nLanguageIndex(stream->GetLanguage()); w |= (streamLangIndex == lang) ? LANGUAGE_MASK : 0; // summed weight weight[w] = stream; } // reorder streams on weight int idx = 0; m_Demuxers.clear(); for(std::map<uint32_t, cTSDemuxer*>::reverse_iterator i = weight.rbegin(); i != weight.rend(); i++, idx++) { cTSDemuxer* stream = i->second; DEBUGLOG("Stream : Type %s / %s Weight: %08X", stream->TypeName(), stream->GetLanguage(), i->first); m_Demuxers.push_back(stream); } }