1 | #include "dvbdescriptors.h" |
---|
2 | #include "iso6937tables.h" |
---|
3 | |
---|
4 | #include <unistd.h> |
---|
5 | #include <qtextcodec.h> |
---|
6 | #include <qdeepcopy.h> |
---|
7 | |
---|
8 | // Only some of the QTextCodec calls are reenterant. |
---|
9 | // If you use this please verify that you are using a reenterant call. |
---|
10 | static const QTextCodec *iso8859_codecs[16] = |
---|
11 | { |
---|
12 | QTextCodec::codecForName("Latin1"), |
---|
13 | QTextCodec::codecForName("ISO8859-1"), // Western |
---|
14 | QTextCodec::codecForName("ISO8859-2"), // Central European |
---|
15 | QTextCodec::codecForName("ISO8859-3"), // Central European |
---|
16 | QTextCodec::codecForName("ISO8859-4"), // Baltic |
---|
17 | QTextCodec::codecForName("ISO8859-5"), // Cyrillic |
---|
18 | QTextCodec::codecForName("ISO8859-6"), // Arabic |
---|
19 | QTextCodec::codecForName("ISO8859-7"), // Greek |
---|
20 | QTextCodec::codecForName("ISO8859-8"), // Hebrew, visually ordered |
---|
21 | QTextCodec::codecForName("ISO8859-9"), // Turkish |
---|
22 | QTextCodec::codecForName("ISO8859-10"), |
---|
23 | QTextCodec::codecForName("ISO8859-11"), |
---|
24 | QTextCodec::codecForName("ISO8859-12"), |
---|
25 | QTextCodec::codecForName("ISO8859-13"), |
---|
26 | QTextCodec::codecForName("ISO8859-14"), |
---|
27 | QTextCodec::codecForName("ISO8859-15"), // Western |
---|
28 | }; |
---|
29 | |
---|
30 | static QString decode_iso6937(const unsigned char *buf, uint length) |
---|
31 | { |
---|
32 | // ISO/IEC 6937 to unicode (UCS2) convertor... |
---|
33 | // This is a composed encoding - accent first then plain character |
---|
34 | QString result = ""; |
---|
35 | ushort ch = 0x20; |
---|
36 | for (uint i = 0; (i < length) && buf[i]; i++) |
---|
37 | { |
---|
38 | if (ch == 0xFFFF) |
---|
39 | { |
---|
40 | // Process second byte of two byte character |
---|
41 | ch = iso6937table_secondary[buf[i-1]][buf[i]]; |
---|
42 | if (ch == 0xFFFF) |
---|
43 | { |
---|
44 | // If no valid code found in secondary table, |
---|
45 | // reprocess this second byte as first byte. |
---|
46 | ch = iso6937table_base[buf[i]]; |
---|
47 | if (ch == 0xFFFF) |
---|
48 | continue; // process second byte |
---|
49 | } |
---|
50 | } |
---|
51 | else |
---|
52 | { |
---|
53 | // Process first character of two possible characters. |
---|
54 | // double byte characters have a sentinel (0xffff) in this table. |
---|
55 | ch = iso6937table_base[buf[i]]; |
---|
56 | if (ch == 0xFFFF) |
---|
57 | continue; // process second byte |
---|
58 | |
---|
59 | } |
---|
60 | result += QChar(ch); |
---|
61 | } |
---|
62 | return result; |
---|
63 | } |
---|
64 | |
---|
65 | // Decode a text string according to ETSI EN 300 468 Annex A |
---|
66 | QString dvb_decode_text(const unsigned char *src, uint raw_length, |
---|
67 | const unsigned char *encoding_override, |
---|
68 | uint encoding_override_length) |
---|
69 | { |
---|
70 | if (!raw_length) |
---|
71 | return ""; |
---|
72 | |
---|
73 | if ((0x10 < src[0]) && (src[0] < 0x20)) |
---|
74 | { |
---|
75 | // TODO: Handle multi-byte encodings |
---|
76 | VERBOSE(VB_SIPARSER, "dvb_decode_text: " |
---|
77 | "Multi-byte coded text is not yet supported."); |
---|
78 | return ""; |
---|
79 | } |
---|
80 | |
---|
81 | // Strip formatting characters |
---|
82 | // Also, if a override encoding is specified copy it in front of the text |
---|
83 | unsigned char dst[raw_length + encoding_override_length]; |
---|
84 | uint length = encoding_override_length; |
---|
85 | if (encoding_override) |
---|
86 | memcpy(dst, encoding_override, encoding_override_length); |
---|
87 | |
---|
88 | for (uint i = 0; i < raw_length; i++) |
---|
89 | { |
---|
90 | if ((src[i] < 0x80) || (src[i] > 0x9F)) |
---|
91 | { |
---|
92 | dst[length] = src[i]; |
---|
93 | length++; |
---|
94 | } |
---|
95 | } |
---|
96 | const unsigned char *buf = dst; |
---|
97 | |
---|
98 | // Exit on empty string, sans formatting. |
---|
99 | if (!length) |
---|
100 | return ""; |
---|
101 | |
---|
102 | // Decode using the correct text codec |
---|
103 | if (buf[0] >= 0x20) |
---|
104 | { |
---|
105 | return decode_iso6937(buf, length); |
---|
106 | } |
---|
107 | else if ((buf[0] >= 0x01) && (buf[0] <= 0x0B)) |
---|
108 | { |
---|
109 | return iso8859_codecs[4 + buf[0]]->toUnicode((char*)(buf + 1), length - 1); |
---|
110 | } |
---|
111 | else if (buf[0] == 0x10) |
---|
112 | { |
---|
113 | // If the first byte of the text field has a value "0x10" |
---|
114 | // then the following two bytes carry a 16-bit value (uimsbf) N |
---|
115 | // to indicate that the remaining data of the text field is |
---|
116 | // coded using the character code table specified by |
---|
117 | // ISO Standard 8859, parts 1 to 9 |
---|
118 | |
---|
119 | uint code = buf[1] << 8 | buf[2]; |
---|
120 | if (code <= 15) |
---|
121 | return iso8859_codecs[code]->toUnicode((char*)(buf + 3), length - 3); |
---|
122 | else |
---|
123 | return QString::fromLocal8Bit((char*)(buf + 3), length - 3); |
---|
124 | } |
---|
125 | else |
---|
126 | { |
---|
127 | // Unknown/invalid encoding - assume local8Bit |
---|
128 | return QString::fromLocal8Bit((char*)(buf + 1), length - 1); |
---|
129 | } |
---|
130 | |
---|
131 | } |
---|
132 | |
---|
133 | QMutex ContentDescriptor::categoryLock; |
---|
134 | map<uint,QString> ContentDescriptor::categoryDesc; |
---|
135 | bool ContentDescriptor::categoryDescExists = false; |
---|
136 | |
---|
137 | QString myth_category_type_to_string(uint category_type) |
---|
138 | { |
---|
139 | static const char *cattype[] = |
---|
140 | { "", "movie", "series", "sports", "tvshow", }; |
---|
141 | |
---|
142 | if ((category_type > kCategoryNone) && (category_type < kCategoryLast)) |
---|
143 | return QString(cattype[category_type]); |
---|
144 | |
---|
145 | return QString::null; |
---|
146 | } |
---|
147 | |
---|
148 | MythCategoryType string_to_myth_category_type(const QString &category_type) |
---|
149 | { |
---|
150 | static const char *cattype[] = |
---|
151 | { "", "movie", "series", "sports", "tvshow", }; |
---|
152 | |
---|
153 | for (uint i = 1; i < 5; i++) |
---|
154 | if (category_type == cattype[i]) |
---|
155 | return (MythCategoryType) i; |
---|
156 | return kCategoryNone; |
---|
157 | } |
---|
158 | |
---|
159 | MythCategoryType ContentDescriptor::GetMythCategory(uint i) const |
---|
160 | { |
---|
161 | if (0x1 == Nibble1(i)) |
---|
162 | return kCategoryMovie; |
---|
163 | if (0x4 == Nibble1(i)) |
---|
164 | return kCategorySports; |
---|
165 | return kCategoryTVShow; |
---|
166 | } |
---|
167 | |
---|
168 | QString ContentDescriptor::GetDescription(uint i) const |
---|
169 | { |
---|
170 | if (!categoryDescExists) |
---|
171 | Init(); |
---|
172 | |
---|
173 | QMutexLocker locker(&categoryLock); |
---|
174 | |
---|
175 | // Try to get detailed description |
---|
176 | map<uint,QString>::const_iterator it = categoryDesc.find(Nibble(i)); |
---|
177 | if (it != categoryDesc.end()) |
---|
178 | return QDeepCopy<QString>((*it).second); |
---|
179 | |
---|
180 | // Fall back to category description |
---|
181 | it = categoryDesc.find(Nibble1(i)<<4); |
---|
182 | if (it != categoryDesc.end()) |
---|
183 | return QDeepCopy<QString>((*it).second); |
---|
184 | |
---|
185 | // Found nothing? Just return empty string. |
---|
186 | return ""; |
---|
187 | } |
---|
188 | |
---|
189 | QString ContentDescriptor::toString() const |
---|
190 | { |
---|
191 | QString tmp(""); |
---|
192 | for (uint i = 0; i < Count(); i++) |
---|
193 | tmp += GetMythCategory(i) + " : " + GetDescription(i); |
---|
194 | return tmp; |
---|
195 | } |
---|
196 | |
---|
197 | void ContentDescriptor::Init(void) |
---|
198 | { |
---|
199 | QMutexLocker locker(&categoryLock); |
---|
200 | |
---|
201 | if (categoryDescExists) |
---|
202 | return; |
---|
203 | |
---|
204 | categoryDesc[0x10] = QObject::tr("Movie"); |
---|
205 | categoryDesc[0x11] = QObject::tr("Movie") + " - " + |
---|
206 | QObject::tr("Detective/Thriller"); |
---|
207 | categoryDesc[0x12] = QObject::tr("Movie")+ " - " + |
---|
208 | QObject::tr("Adventure/Western/War"); |
---|
209 | categoryDesc[0x13] = QObject::tr("Movie")+ " - " + |
---|
210 | QObject::tr("Science Fiction/Fantasy/Horror"); |
---|
211 | categoryDesc[0x14] = QObject::tr("Movie")+ " - " + |
---|
212 | QObject::tr("Comedy"); |
---|
213 | categoryDesc[0x15] = QObject::tr("Movie")+ " - " + |
---|
214 | QObject::tr("Soap/melodrama/folkloric"); |
---|
215 | categoryDesc[0x16] = QObject::tr("Movie")+ " - " + |
---|
216 | QObject::tr("Romance"); |
---|
217 | categoryDesc[0x17] = QObject::tr("Movie")+ " - " + |
---|
218 | QObject::tr("Serious/Classical/Religious/Historical Movie/Drama"); |
---|
219 | categoryDesc[0x18] = QObject::tr("Movie")+ " - " + |
---|
220 | QObject::tr("Adult", "Adult Movie"); |
---|
221 | |
---|
222 | categoryDesc[0x20] = QObject::tr("News"); |
---|
223 | categoryDesc[0x21] = QObject::tr("News/weather report"); |
---|
224 | categoryDesc[0x22] = QObject::tr("News magazine"); |
---|
225 | categoryDesc[0x23] = QObject::tr("Documentary"); |
---|
226 | categoryDesc[0x24] = QObject::tr("Intelligent Programmes"); |
---|
227 | |
---|
228 | categoryDesc[0x30] = QObject::tr("Show/game Show"); |
---|
229 | categoryDesc[0x31] = QObject::tr("Game Show"); |
---|
230 | categoryDesc[0x32] = QObject::tr("Variety Show"); |
---|
231 | categoryDesc[0x33] = QObject::tr("Talk Show"); |
---|
232 | |
---|
233 | categoryDesc[0x40] = QObject::tr("Sports"); |
---|
234 | categoryDesc[0x41] = |
---|
235 | QObject::tr("Special Events (World Cup, World Series..)"); |
---|
236 | categoryDesc[0x42] = QObject::tr("Sports Magazines"); |
---|
237 | categoryDesc[0x43] = QObject::tr("Football (Soccer)"); |
---|
238 | categoryDesc[0x44] = QObject::tr("Tennis/Squash"); |
---|
239 | categoryDesc[0x45] = |
---|
240 | QObject::tr("Misc. Team Sports"); // not football/soccer |
---|
241 | categoryDesc[0x46] = QObject::tr("Athletics"); |
---|
242 | categoryDesc[0x47] = QObject::tr("Motor Sport"); |
---|
243 | categoryDesc[0x48] = QObject::tr("Water Sport"); |
---|
244 | categoryDesc[0x49] = QObject::tr("Winter Sports"); |
---|
245 | categoryDesc[0x4A] = QObject::tr("Equestrian"); |
---|
246 | categoryDesc[0x4B] = QObject::tr("Martial Sports"); |
---|
247 | |
---|
248 | categoryDesc[0x50] = QObject::tr("Kids"); |
---|
249 | categoryDesc[0x51] = QObject::tr("Pre-School Children's Programmes"); |
---|
250 | categoryDesc[0x52] = QObject::tr("Entertainment Programmes for 6 to 14"); |
---|
251 | categoryDesc[0x53] = QObject::tr("Entertainment Programmes for 10 to 16"); |
---|
252 | categoryDesc[0x54] = QObject::tr("Informational/Educational"); |
---|
253 | categoryDesc[0x55] = QObject::tr("Cartoons/Puppets"); |
---|
254 | |
---|
255 | categoryDesc[0x60] = QObject::tr("Music/Ballet/Dance"); |
---|
256 | categoryDesc[0x61] = QObject::tr("Rock/Pop"); |
---|
257 | categoryDesc[0x62] = QObject::tr("Classical Music"); |
---|
258 | categoryDesc[0x63] = QObject::tr("Folk Music"); |
---|
259 | categoryDesc[0x64] = QObject::tr("Jazz"); |
---|
260 | categoryDesc[0x65] = QObject::tr("Musical/Opera"); |
---|
261 | categoryDesc[0x66] = QObject::tr("Ballet"); |
---|
262 | |
---|
263 | categoryDesc[0x70] = QObject::tr("Arts/Culture"); |
---|
264 | categoryDesc[0x71] = QObject::tr("Performing Arts"); |
---|
265 | categoryDesc[0x72] = QObject::tr("Fine Arts"); |
---|
266 | categoryDesc[0x73] = QObject::tr("Religion"); |
---|
267 | categoryDesc[0x74] = QObject::tr("Popular Culture/Traditional Arts"); |
---|
268 | categoryDesc[0x75] = QObject::tr("Literature"); |
---|
269 | categoryDesc[0x76] = QObject::tr("Film/Cinema"); |
---|
270 | categoryDesc[0x77] = QObject::tr("Experimental Film/Video"); |
---|
271 | categoryDesc[0x78] = QObject::tr("Broadcasting/Press"); |
---|
272 | categoryDesc[0x79] = QObject::tr("New Media"); |
---|
273 | categoryDesc[0x7A] = QObject::tr("Arts/Culture Magazines"); |
---|
274 | categoryDesc[0x7B] = QObject::tr("Fashion"); |
---|
275 | |
---|
276 | categoryDesc[0x80] = QObject::tr("Social/Policical/Economics"); |
---|
277 | categoryDesc[0x81] = QObject::tr("Magazines/Reports/Documentary"); |
---|
278 | categoryDesc[0x82] = QObject::tr("Economics/Social Advisory"); |
---|
279 | categoryDesc[0x83] = QObject::tr("Remarkable People"); |
---|
280 | |
---|
281 | categoryDesc[0x90] = QObject::tr("Education/Science/Factual"); |
---|
282 | categoryDesc[0x91] = QObject::tr("Nature/animals/Environment"); |
---|
283 | categoryDesc[0x92] = QObject::tr("Technology/Natural Sciences"); |
---|
284 | categoryDesc[0x93] = QObject::tr("Medicine/Physiology/Psychology"); |
---|
285 | categoryDesc[0x94] = QObject::tr("Foreign Countries/Expeditions"); |
---|
286 | categoryDesc[0x95] = QObject::tr("Social/Spiritual Sciences"); |
---|
287 | categoryDesc[0x96] = QObject::tr("Further Education"); |
---|
288 | categoryDesc[0x97] = QObject::tr("Languages"); |
---|
289 | |
---|
290 | categoryDesc[0xA0] = QObject::tr("Leisure/Hobbies"); |
---|
291 | categoryDesc[0xA1] = QObject::tr("Tourism/Travel"); |
---|
292 | categoryDesc[0xA2] = QObject::tr("Handicraft"); |
---|
293 | categoryDesc[0xA3] = QObject::tr("Motoring"); |
---|
294 | categoryDesc[0xA4] = QObject::tr("Fitness & Health"); |
---|
295 | categoryDesc[0xA5] = QObject::tr("Cooking"); |
---|
296 | categoryDesc[0xA6] = QObject::tr("Advertizement/Shopping"); |
---|
297 | categoryDesc[0xA7] = QObject::tr("Gardening"); |
---|
298 | // Special |
---|
299 | categoryDesc[0xB0] = QObject::tr("Original Language"); |
---|
300 | categoryDesc[0xB1] = QObject::tr("Black & White"); |
---|
301 | categoryDesc[0xB2] = QObject::tr("\"Unpublished\" Programmes"); |
---|
302 | categoryDesc[0xB3] = QObject::tr("Live Broadcast"); |
---|
303 | // UK Freeview custom id |
---|
304 | categoryDesc[0xF0] = QObject::tr("Drama"); |
---|
305 | |
---|
306 | categoryDescExists = true; |
---|
307 | } |
---|
308 | |
---|
309 | QString FrequencyListDescriptor::toString() const |
---|
310 | { |
---|
311 | QString str = "FrequencyListDescriptor: frequencies: "; |
---|
312 | |
---|
313 | for (uint i = 0; i < FrequencyCount(); i++) |
---|
314 | str.append(QString(" %1").arg(FrequencyHz(i))); |
---|
315 | |
---|
316 | return str; |
---|
317 | } |
---|
318 | |
---|
319 | QString ServiceDescriptor::toString() const |
---|
320 | { |
---|
321 | QString str = QString("ServiceDescriptor: %1").arg(ServiceName()); |
---|
322 | |
---|
323 | if (IsDTV()) |
---|
324 | str.append(" (TV)"); |
---|
325 | else if (IsDigitalAudio()) |
---|
326 | str.append(" (Radio)"); |
---|
327 | else if (IsHDTV()) |
---|
328 | str.append(" (HDTV)"); |
---|
329 | else if (IsTeletext()) |
---|
330 | str.append(" (Teletext)"); |
---|
331 | else |
---|
332 | str.append(QString(" (Unknown %1)").arg(ServiceType(),2,16)); |
---|
333 | |
---|
334 | return str; |
---|
335 | } |
---|
336 | |
---|
337 | QString CableDeliverySystemDescriptor::toString() const |
---|
338 | { |
---|
339 | QString str = QString("CableDeliverySystemDescriptor: "); |
---|
340 | |
---|
341 | str.append(QString("Frequency: %1\n").arg(FrequencyHz())); |
---|
342 | str.append(QString(" Mod=%1, SymbR=%2, FECInner=%3, FECOuter=%4") |
---|
343 | .arg(ModulationString()) |
---|
344 | .arg(SymbolRateHz()) |
---|
345 | .arg(FECInnerString()) |
---|
346 | .arg(FECOuterString())); |
---|
347 | |
---|
348 | return str; |
---|
349 | } |
---|
350 | |
---|
351 | QString SatelliteDeliverySystemDescriptor::toString() const |
---|
352 | { |
---|
353 | QString str = QString("SatelliteDeliverySystemDescriptor: "); |
---|
354 | |
---|
355 | str.append(QString("Frequency: %1\n").arg(FrequencyHz())); |
---|
356 | str.append(QString(" Mod=%1, SymbR=%2, FECInner=%3, Orbit=%4, Pol=%5") |
---|
357 | .arg(ModulationString()) |
---|
358 | .arg(SymbolRateHz()) |
---|
359 | .arg(FECInnerString()) |
---|
360 | .arg(OrbitalPositionString()) |
---|
361 | .arg(PolarizationString())); |
---|
362 | |
---|
363 | return str; |
---|
364 | } |
---|
365 | |
---|
366 | QString TerrestrialDeliverySystemDescriptor::toString() const |
---|
367 | { |
---|
368 | QString str = QString("TerrestrialDeliverySystemDescriptor: "); |
---|
369 | |
---|
370 | str.append(QString("Frequency: %1\n").arg(FrequencyHz())); |
---|
371 | str.append(QString(" BW=%1k, C=%2, HP=%3, LP=%4, GI=%5, TransMode=%6k") |
---|
372 | .arg(BandwidthString()) |
---|
373 | .arg(ConstellationString()) |
---|
374 | .arg(CodeRateHPString()) |
---|
375 | .arg(CodeRateLPString()) |
---|
376 | .arg(GuardIntervalString()) |
---|
377 | .arg(TransmissionModeString())); |
---|
378 | |
---|
379 | return str; |
---|
380 | } |
---|
381 | |
---|