vdr  2.0.4
si.c
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (c) 2003 by Marcel Wiesweg *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation; either version 2 of the License, or *
7  * (at your option) any later version. *
8  * *
9  * $Id: si.c 2.8 2012/09/29 14:44:20 kls Exp $
10  * *
11  ***************************************************************************/
12 
13 #include "si.h"
14 #include <errno.h>
15 #include <iconv.h>
16 #include <malloc.h>
17 #include <stdlib.h> // for broadcaster stupidity workaround
18 #include <string.h>
19 #include "descriptor.h"
20 
21 namespace SI {
22 
24 }
25 
26 Object::Object(CharArray &d) : data(d) {
27 }
28 
29 void Object::setData(const unsigned char*d, int size, bool doCopy) {
30  data.assign(d, size, doCopy);
31 }
32 
34  data=d;
35 }
36 
37 bool Object::checkSize(int offset) {
38  return data.checkSize(offset);
39 }
40 
41 Section::Section(const unsigned char *data, bool doCopy) {
42  setData(data, getLength(data), doCopy);
43 }
44 
46  return getTableId(data.getData());
47 }
48 
50  return getLength(data.getData());
51 }
52 
53 TableId Section::getTableId(const unsigned char *d) {
54  return (TableId)((const SectionHeader *)d)->table_id;
55 }
56 
57 int Section::getLength(const unsigned char *d) {
58  return HILO(((const SectionHeader *)d)->section_length)+sizeof(SectionHeader);
59 }
60 
62  return CRC32::isValid((const char *)data.getData(), getLength()/*, data.FourBytes(getLength()-4)*/);
63 }
64 
66  if (!isCRCValid())
67  return false;
68  CheckParse();
69  return isValid();
70 }
71 
74 }
75 
76 int NumberedSection::getTableIdExtension(const unsigned char *d) {
77  return HILO(((const ExtendedSectionHeader *)d)->table_id_extension);
78 }
79 
81  return data.getData<ExtendedSectionHeader>()->current_next_indicator;
82 }
83 
85  return data.getData<ExtendedSectionHeader>()->version_number;
86 }
87 
89  return data.getData<ExtendedSectionHeader>()->section_number;
90 }
91 
93  return data.getData<ExtendedSectionHeader>()->last_section_number;
94 }
95 
97  return getLength(data.getData());
98 }
99 
101  return getDescriptorTag(data.getData());
102 }
103 
104 int Descriptor::getLength(const unsigned char *d) {
105  return ((const DescriptorHeader*)d)->descriptor_length+sizeof(DescriptorHeader);
106 }
107 
109  return (DescriptorTag)((const DescriptorHeader*)d)->descriptor_tag;
110 }
111 
113  if (isValid() && it.i<getLength()) {
114  return createDescriptor(it.i, true);
115  }
116  return 0;
117 }
118 
119 Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor) {
120  Descriptor *d=0;
121  int len;
122  if (isValid() && it.i<(len=getLength())) {
123  const unsigned char *p=data.getData(it.i);
124  const unsigned char *end=p+len-it.i;
125  while (p < end) {
126  if (Descriptor::getDescriptorTag(p) == tag) {
127  d=createDescriptor(it.i, returnUnimplemetedDescriptor);
128  if (d)
129  break;
130  }
131  it.i+=Descriptor::getLength(p);
132  p+=Descriptor::getLength(p);
133  }
134  }
135  return d;
136 }
137 
138 Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplementedDescriptor) {
139  Descriptor *d=0;
140  int len;
141  if (isValid() && it.i<(len=getLength())) {
142  const unsigned char *p=data.getData(it.i);
143  const unsigned char *end=p+len-it.i;
144  while (p < end) {
145  for (int u=0; u<arrayLength;u++)
146  if (Descriptor::getDescriptorTag(p) == tags[u]) {
147  d=createDescriptor(it.i, returnUnimplementedDescriptor);
148  break;
149  }
150  if (d)
151  break; //length is added to it.i by createDescriptor, break here
152  it.i+=Descriptor::getLength(p);
153  p+=Descriptor::getLength(p);
154  }
155  }
156  return d;
157 }
158 
159 Descriptor *DescriptorLoop::createDescriptor(int &i, bool returnUnimplemetedDescriptor) {
161  return 0;
162  Descriptor *d=Descriptor::getDescriptor(data+i, domain, returnUnimplemetedDescriptor);
163  if (!d)
164  return 0;
165  i+=d->getLength();
166  d->CheckParse();
167  return d;
168 }
169 
171  const unsigned char *p=data.getData();
172  const unsigned char *end=p+getLength();
173  int count=0;
174  while (p < end) {
175  count++;
176  p+=Descriptor::getLength(p);
177  }
178  return count;
179 }
180 
182  array=0;
183  length=0;
185 }
186 
189  Delete();
190  delete[] array;
191 }
192 
194  for (int i=0;i<length;i++)
195  if (array[i]!=0) {
196  delete array[i];
197  array[i]=0;
198  }
199 }
200 
202  if (!array) {
204  array=new GroupDescriptor*[length]; //numbering is zero-based
205  for (int i=0;i<length;i++)
206  array[i]=0;
207  } else if (length != d->getLastDescriptorNumber()+1)
208  return; //avoid crash in case of misuse
209  if (length <= d->getDescriptorNumber())
210  return; // see http://www.vdr-portal.de/board60-linux/board14-betriebssystem/board69-c-t-vdr/p1025777-segfault-mit-vdr-1-7-21/#post1025777
211  array[d->getDescriptorNumber()]=d;
212 }
213 
215  for (int i=0;i<length;i++)
216  if (array[i]==0)
217  return false;
218  return true;
219 }
220 
222  int len=getLength();
223  if (len < 0 || len > 4095)
224  return strdup("text error"); // caller will delete it!
225  char *data=new char(len+1); // FIXME If this function is ever actually used, this buffer might
226  // need to be bigger in order to hold the string as UTF-8.
227  // Maybe decodeText should dynamically handle this? kls 2007-06-10
228  decodeText(data, len+1);
229  return data;
230 }
231 
232 char *String::getText(char *buffer, int size) {
233  int len=getLength();
234  if (len < 0 || len >= size) {
235  strncpy(buffer, "text error", size);
236  buffer[size-1] = 0;
237  return buffer;
238  }
239  decodeText(buffer, size);
240  return buffer;
241 }
242 
243 char *String::getText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) {
244  int len=getLength();
245  if (len < 0 || len >= sizeBuffer) {
246  strncpy(buffer, "text error", sizeBuffer);
247  buffer[sizeBuffer-1] = 0;
248  *shortVersion = 0;
249  return buffer;
250  }
251  decodeText(buffer, shortVersion, sizeBuffer, sizeShortVersion);
252  return buffer;
253 }
254 
255 static const char *CharacterTables1[] = {
256  NULL, // 0x00
257  "ISO-8859-5", // 0x01
258  "ISO-8859-6", // 0x02
259  "ISO-8859-7", // 0x03
260  "ISO-8859-8", // 0x04
261  "ISO-8859-9", // 0x05
262  "ISO-8859-10", // 0x06
263  "ISO-8859-11", // 0x07
264  "ISO-8859-12", // 0x08
265  "ISO-8859-13", // 0x09
266  "ISO-8859-14", // 0x0A
267  "ISO-8859-15", // 0x0B
268  NULL, // 0x0C
269  NULL, // 0x0D
270  NULL, // 0x0E
271  NULL, // 0x0F
272  NULL, // 0x10
273  "UTF-16", // 0x11
274  "EUC-KR", // 0x12
275  "GB2312", // 0x13
276  "GBK", // 0x14
277  "UTF-8", // 0x15
278  NULL, // 0x16
279  NULL, // 0x17
280  NULL, // 0x18
281  NULL, // 0x19
282  NULL, // 0x1A
283  NULL, // 0x1B
284  NULL, // 0x1C
285  NULL, // 0x1D
286  NULL, // 0x1E
287  NULL, // 0x1F
288 };
289 
290 #define SingleByteLimit 0x0B
291 
292 static const char *CharacterTables2[] = {
293  NULL, // 0x00
294  "ISO-8859-1", // 0x01
295  "ISO-8859-2", // 0x02
296  "ISO-8859-3", // 0x03
297  "ISO-8859-4", // 0x04
298  "ISO-8859-5", // 0x05
299  "ISO-8859-6", // 0x06
300  "ISO-8859-7", // 0x07
301  "ISO-8859-8", // 0x08
302  "ISO-8859-9", // 0x09
303  "ISO-8859-10", // 0x0A
304  "ISO-8859-11", // 0x0B
305  NULL, // 0x0C
306  "ISO-8859-13", // 0x0D
307  "ISO-8859-14", // 0x0E
308  "ISO-8859-15", // 0x0F
309 };
310 
311 #define NumEntries(Table) (sizeof(Table) / sizeof(char *))
312 
313 static const char *SystemCharacterTable = NULL;
315 
317 {
319 }
320 
321 bool SetSystemCharacterTable(const char *CharacterTable) {
322  if (CharacterTable) {
323  for (unsigned int i = 0; i < NumEntries(CharacterTables1); i++) {
324  if (CharacterTables1[i] && strcasecmp(CharacterTable, CharacterTables1[i]) == 0) {
327  return true;
328  }
329  }
330  for (unsigned int i = 0; i < NumEntries(CharacterTables2); i++) {
331  if (CharacterTables2[i] && strcasecmp(CharacterTable, CharacterTables2[i]) == 0) {
334  return true;
335  }
336  }
337  } else {
338  SystemCharacterTable = NULL;
340  return true;
341  }
342  return false;
343 }
344 
345 const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte) {
346  const char *cs = "ISO6937";
347  // Workaround for broadcaster stupidity: according to
348  // "ETSI EN 300 468" the default character set is ISO6937. But unfortunately some
349  // broadcasters actually use ISO-8859-9, but fail to correctly announce that.
350  static const char *CharsetOverride = getenv("VDR_CHARSET_OVERRIDE");
351  if (CharsetOverride)
352  cs = CharsetOverride;
353  if (isSingleByte)
354  *isSingleByte = false;
355  if (length <= 0)
356  return cs;
357  unsigned int tag = buffer[0];
358  if (tag >= 0x20)
359  return cs;
360  if (tag == 0x10) {
361  if (length >= 3) {
362  tag = (buffer[1] << 8) | buffer[2];
363  if (tag < NumEntries(CharacterTables2) && CharacterTables2[tag]) {
364  buffer += 3;
365  length -= 3;
366  if (isSingleByte)
367  *isSingleByte = true;
368  return CharacterTables2[tag];
369  }
370  }
371  } else if (tag < NumEntries(CharacterTables1) && CharacterTables1[tag]) {
372  buffer += 1;
373  length -= 1;
374  if (isSingleByte)
375  *isSingleByte = tag <= SingleByteLimit;
376  return CharacterTables1[tag];
377  }
378  return cs;
379 }
380 
381 bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode)
382 {
383  if (SystemCharacterTable) {
384  iconv_t cd = iconv_open(SystemCharacterTable, fromCode);
385  if (cd != (iconv_t)-1) {
386  char *fromPtr = (char *)from;
387  while (fromLength > 0 && toLength > 1) {
388  if (iconv(cd, &fromPtr, &fromLength, &to, &toLength) == size_t(-1)) {
389  if (errno == EILSEQ) {
390  // A character can't be converted, so mark it with '?' and proceed:
391  fromPtr++;
392  fromLength--;
393  *to++ = '?';
394  toLength--;
395  }
396  else
397  break;
398  }
399  }
400  *to = 0;
401  iconv_close(cd);
402  return true;
403  }
404  }
405  return false;
406 }
407 
408 // A similar version is used in VDR/tools.c:
409 static int Utf8CharLen(const char *s)
410 {
412  return 1;
413 #define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
414  if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
415  return 2;
416  if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
417  return 3;
418  if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
419  return 4;
420  return 1;
421 }
422 
423 // originally from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de>
424 void String::decodeText(char *buffer, int size) {
425  const unsigned char *from=data.getData(0);
426  char *to=buffer;
427  int len=getLength();
428  if (len <= 0) {
429  *to = '\0';
430  return;
431  }
432  bool singleByte;
433  const char *cs = getCharacterTable(from, len, &singleByte);
434  if (singleByte && SystemCharacterTableIsSingleByte || !convertCharacterTable((const char *)from, len, to, size, cs)) {
435  if (len >= size)
436  len = size - 1;
437  strncpy(to, (const char *)from, len);
438  to[len] = 0;
439  }
440  else
441  len = strlen(to); // might have changed
442  // Handle control codes:
443  while (len > 0) {
444  int l = Utf8CharLen(to);
445  if (l <= 2) {
446  unsigned char *p = (unsigned char *)to;
447  if (l == 2 && *p == 0xC2) // UTF-8 sequence
448  p++;
449  bool Move = true;
450  switch (*p) {
451  case 0x8A: *to = '\n'; break;
452  case 0xA0: *to = ' '; break;
453  default: Move = false;
454  }
455  if (l == 2 && Move) {
456  memmove(p, p + 1, len - 1); // we also copy the terminating 0!
457  len -= 1;
458  l = 1;
459  }
460  }
461  to += l;
462  len -= l;
463  }
464 }
465 
466 void String::decodeText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) {
467  decodeText(buffer, sizeBuffer);
468  if (!*buffer) {
469  *shortVersion = '\0';
470  return;
471  }
472  // Handle control codes:
473  char *to=buffer;
474  int len=strlen(to);
475  int IsShortName=0;
476  while (len > 0) {
477  int l = Utf8CharLen(to);
478  unsigned char *p = (unsigned char *)to;
479  if (l == 2 && *p == 0xC2) // UTF-8 sequence
480  p++;
481  if (*p == 0x86 || *p == 0x87) {
482  IsShortName += (*p == 0x86) ? 1 : -1;
483  memmove(to, to + l, len - l + 1); // we also copy the terminating 0!
484  len -= l;
485  l = 0;
486  }
487  if (l && IsShortName) {
488  if (l < sizeShortVersion) {
489  for (int i = 0; i < l; i++)
490  *shortVersion++ = to[i];
491  sizeShortVersion -= l;
492  }
493  }
494  to += l;
495  len -= l;
496  }
497  *shortVersion = '\0';
498 }
499 
500 Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor) {
501  Descriptor *d=0;
502  switch (domain) {
503  case SI:
505  case CaDescriptorTag:
506  d=new CaDescriptor();
507  break;
510  break;
512  d=new NetworkNameDescriptor();
513  break;
515  d=new ServiceListDescriptor();
516  break;
519  break;
522  break;
525  break;
527  d=new BouquetNameDescriptor();
528  break;
530  d=new ServiceDescriptor();
531  break;
533  d=new NVODReferenceDescriptor();
534  break;
537  break;
539  d=new ComponentDescriptor();
540  break;
543  break;
545  d=new SubtitlingDescriptor();
546  break;
549  break;
552  break;
555  break;
558  break;
561  break;
563  d=new ServiceMoveDescriptor();
564  break;
566  d=new FrequencyListDescriptor();
567  break;
570  break;
572  d=new CaIdentifierDescriptor();
573  break;
575  d=new ShortEventDescriptor();
576  break;
578  d=new ExtendedEventDescriptor();
579  break;
582  break;
584  d=new ContentDescriptor();
585  break;
587  d=new ParentalRatingDescriptor();
588  break;
591  d=new TeletextDescriptor();
592  break;
595  break;
598  break;
600  d=new LinkageDescriptor();
601  break;
603  d=new ISO639LanguageDescriptor();
604  break;
605  case PDCDescriptorTag:
606  d=new PDCDescriptor();
607  break;
609  d=new AncillaryDataDescriptor();
610  break;
613  break;
615  d=new ExtensionDescriptor();
616  break;
618  d=new RegistrationDescriptor();
619  break;
622  break;
625  break;
626 
627  //note that it is no problem to implement one
628  //of the unimplemented descriptors.
629 
630  //defined in ISO-13818-1
643  case STDDescriptorTag:
644  case IBPDescriptorTag:
645 
646  //defined in ETSI EN 300 468
650  case MocaicDescriptorTag:
660  case AC3DescriptorTag:
661  case DSNGDescriptorTag:
665 
666  //defined in ETSI EN 300 468 v 1.7.1
668  case TVAIdDescriptorTag:
672  case DTSDescriptorTag:
673  case AACDescriptorTag:
674  default:
675  if (!returnUnimplemetedDescriptor)
676  return 0;
677  d=new UnimplementedDescriptor();
678  break;
679  }
680  break;
681  case MHP:
683  // They once again start with 0x00 (see page 234, MHP specification)
686  break;
689  break;
692  break;
695  break;
698  break;
701  break;
702  // 0x05 - 0x0A is unimplemented this library
713  default:
714  if (!returnUnimplemetedDescriptor)
715  return 0;
716  d=new UnimplementedDescriptor();
717  break;
718  }
719  break;
720  case PCIT:
723  d=new ContentDescriptor();
724  break;
726  d=new ShortEventDescriptor();
727  break;
729  d=new ExtendedEventDescriptor();
730  break;
733  break;
734  default:
735  if (!returnUnimplemetedDescriptor)
736  return 0;
737  d=new UnimplementedDescriptor();
738  break;
739  }
740  break;
741  default: ; // unknown domain, nothing to do
742  }
743  d->setData(da);
744  return d;
745 }
746 
747 } //end of namespace
748