vdr  2.2.0
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 3.3 2015/02/10 13:42:41 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 
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 
73  return getTableIdExtension(data.getData());
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;
184  deleteOnDesctruction=del;
185 }
186 
188  if (deleteOnDesctruction)
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) {
203  length=d->getLastDescriptorNumber()+1;
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 false; //avoid crash in case of misuse
209  if (length <= d->getDescriptorNumber())
210  return false; // 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  return true;
213 }
214 
216  for (int i=0;i<length;i++)
217  if (array[i]==0)
218  return false;
219  return true;
220 }
221 
223  int len=getLength();
224  if (len < 0 || len > 4095)
225  return strdup("text error"); // caller will delete it!
226  char *data=new char(len+1); // FIXME If this function is ever actually used, this buffer might
227  // need to be bigger in order to hold the string as UTF-8.
228  // Maybe decodeText should dynamically handle this? kls 2007-06-10
229  decodeText(data, len+1);
230  return data;
231 }
232 
233 char *String::getText(char *buffer, int size) {
234  int len=getLength();
235  if (len < 0 || len >= size) {
236  strncpy(buffer, "text error", size);
237  buffer[size-1] = 0;
238  return buffer;
239  }
240  decodeText(buffer, size);
241  return buffer;
242 }
243 
244 char *String::getText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) {
245  int len=getLength();
246  if (len < 0 || len >= sizeBuffer) {
247  strncpy(buffer, "text error", sizeBuffer);
248  buffer[sizeBuffer-1] = 0;
249  *shortVersion = 0;
250  return buffer;
251  }
252  decodeText(buffer, shortVersion, sizeBuffer, sizeShortVersion);
253  return buffer;
254 }
255 
256 static const char *CharacterTables1[] = {
257  NULL, // 0x00
258  "ISO-8859-5", // 0x01
259  "ISO-8859-6", // 0x02
260  "ISO-8859-7", // 0x03
261  "ISO-8859-8", // 0x04
262  "ISO-8859-9", // 0x05
263  "ISO-8859-10", // 0x06
264  "ISO-8859-11", // 0x07
265  "ISO-8859-12", // 0x08
266  "ISO-8859-13", // 0x09
267  "ISO-8859-14", // 0x0A
268  "ISO-8859-15", // 0x0B
269  NULL, // 0x0C
270  NULL, // 0x0D
271  NULL, // 0x0E
272  NULL, // 0x0F
273  NULL, // 0x10
274  "UTF-16", // 0x11
275  "EUC-KR", // 0x12
276  "GB2312", // 0x13
277  "GBK", // 0x14
278  "UTF-8", // 0x15
279  NULL, // 0x16
280  NULL, // 0x17
281  NULL, // 0x18
282  NULL, // 0x19
283  NULL, // 0x1A
284  NULL, // 0x1B
285  NULL, // 0x1C
286  NULL, // 0x1D
287  NULL, // 0x1E
288  NULL, // 0x1F
289 };
290 
291 #define SingleByteLimit 0x0B
292 
293 static const char *CharacterTables2[] = {
294  NULL, // 0x00
295  "ISO-8859-1", // 0x01
296  "ISO-8859-2", // 0x02
297  "ISO-8859-3", // 0x03
298  "ISO-8859-4", // 0x04
299  "ISO-8859-5", // 0x05
300  "ISO-8859-6", // 0x06
301  "ISO-8859-7", // 0x07
302  "ISO-8859-8", // 0x08
303  "ISO-8859-9", // 0x09
304  "ISO-8859-10", // 0x0A
305  "ISO-8859-11", // 0x0B
306  NULL, // 0x0C
307  "ISO-8859-13", // 0x0D
308  "ISO-8859-14", // 0x0E
309  "ISO-8859-15", // 0x0F
310 };
311 
312 #define NumEntries(Table) (sizeof(Table) / sizeof(char *))
313 
314 static const char *SystemCharacterTable = NULL;
316 
318 {
320 }
321 
322 static char *OverrideCharacterTable = NULL;
323 
324 void SetOverrideCharacterTable(const char *CharacterTable)
325 {
326  free(OverrideCharacterTable);
327  OverrideCharacterTable = CharacterTable ? strdup(CharacterTable) : NULL;
328 }
329 
330 bool SetSystemCharacterTable(const char *CharacterTable) {
331  if (CharacterTable) {
332  for (unsigned int i = 0; i < NumEntries(CharacterTables1); i++) {
333  if (CharacterTables1[i] && strcasecmp(CharacterTable, CharacterTables1[i]) == 0) {
334  SystemCharacterTable = CharacterTables1[i];
335  SystemCharacterTableIsSingleByte = i <= SingleByteLimit;
336  return true;
337  }
338  }
339  for (unsigned int i = 0; i < NumEntries(CharacterTables2); i++) {
340  if (CharacterTables2[i] && strcasecmp(CharacterTable, CharacterTables2[i]) == 0) {
341  SystemCharacterTable = CharacterTables2[i];
342  SystemCharacterTableIsSingleByte = true;
343  return true;
344  }
345  }
346  } else {
347  SystemCharacterTable = NULL;
348  SystemCharacterTableIsSingleByte = true;
349  return true;
350  }
351  return false;
352 }
353 
354 const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte) {
355  const char *cs = "ISO6937";
356  // Workaround for broadcaster stupidity: according to
357  // "ETSI EN 300 468" the default character set is ISO6937. But unfortunately some
358  // broadcasters actually use ISO-8859-9, but fail to correctly announce that.
359  if (OverrideCharacterTable)
361  if (isSingleByte)
362  *isSingleByte = false;
363  if (length <= 0)
364  return cs;
365  unsigned int tag = buffer[0];
366  if (tag >= 0x20)
367  return cs;
368  if (tag == 0x10) {
369  if (length >= 3) {
370  tag = (buffer[1] << 8) | buffer[2];
371  if (tag < NumEntries(CharacterTables2) && CharacterTables2[tag]) {
372  buffer += 3;
373  length -= 3;
374  if (isSingleByte)
375  *isSingleByte = true;
376  return CharacterTables2[tag];
377  }
378  }
379  } else if (tag < NumEntries(CharacterTables1) && CharacterTables1[tag]) {
380  buffer += 1;
381  length -= 1;
382  if (isSingleByte)
383  *isSingleByte = tag <= SingleByteLimit;
384  return CharacterTables1[tag];
385  }
386  return cs;
387 }
388 
389 bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode)
390 {
391  if (SystemCharacterTable) {
392  iconv_t cd = iconv_open(SystemCharacterTable, fromCode);
393  if (cd != (iconv_t)-1) {
394  char *fromPtr = (char *)from;
395  while (fromLength > 0 && toLength > 1) {
396  if (iconv(cd, &fromPtr, &fromLength, &to, &toLength) == size_t(-1)) {
397  if (errno == EILSEQ) {
398  // A character can't be converted, so mark it with '?' and proceed:
399  fromPtr++;
400  fromLength--;
401  *to++ = '?';
402  toLength--;
403  }
404  else
405  break;
406  }
407  }
408  *to = 0;
409  iconv_close(cd);
410  return true;
411  }
412  }
413  return false;
414 }
415 
416 // A similar version is used in VDR/tools.c:
417 static int Utf8CharLen(const char *s)
418 {
419  if (SystemCharacterTableIsSingleByte)
420  return 1;
421 #define MT(s, m, v) ((*(s) & (m)) == (v)) // Mask Test
422  if (MT(s, 0xE0, 0xC0) && MT(s + 1, 0xC0, 0x80))
423  return 2;
424  if (MT(s, 0xF0, 0xE0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80))
425  return 3;
426  if (MT(s, 0xF8, 0xF0) && MT(s + 1, 0xC0, 0x80) && MT(s + 2, 0xC0, 0x80) && MT(s + 3, 0xC0, 0x80))
427  return 4;
428  return 1;
429 }
430 
431 // originally from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de>
432 void String::decodeText(char *buffer, int size) {
433  const unsigned char *from=data.getData(0);
434  char *to=buffer;
435  int len=getLength();
436  if (len <= 0) {
437  *to = '\0';
438  return;
439  }
440  bool singleByte;
441  const char *cs = getCharacterTable(from, len, &singleByte);
442  if (singleByte && SystemCharacterTableIsSingleByte || !convertCharacterTable((const char *)from, len, to, size, cs)) {
443  if (len >= size)
444  len = size - 1;
445  strncpy(to, (const char *)from, len);
446  to[len] = 0;
447  }
448  else
449  len = strlen(to); // might have changed
450  // Handle control codes:
451  while (len > 0) {
452  int l = Utf8CharLen(to);
453  if (l <= 2) {
454  unsigned char *p = (unsigned char *)to;
455  if (l == 2 && *p == 0xC2) // UTF-8 sequence
456  p++;
457  bool Move = true;
458  switch (*p) {
459  case 0x8A: *to = '\n'; break;
460  case 0xA0: *to = ' '; break;
461  default: Move = false;
462  }
463  if (l == 2 && Move) {
464  memmove(p, p + 1, len - 1); // we also copy the terminating 0!
465  len -= 1;
466  l = 1;
467  }
468  }
469  to += l;
470  len -= l;
471  }
472 }
473 
474 void String::decodeText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) {
475  decodeText(buffer, sizeBuffer);
476  if (!*buffer) {
477  *shortVersion = '\0';
478  return;
479  }
480  // Handle control codes:
481  char *to=buffer;
482  int len=strlen(to);
483  int IsShortName=0;
484  while (len > 0) {
485  int l = Utf8CharLen(to);
486  unsigned char *p = (unsigned char *)to;
487  if (l == 2 && *p == 0xC2) // UTF-8 sequence
488  p++;
489  if (*p == 0x86 || *p == 0x87) {
490  IsShortName += (*p == 0x86) ? 1 : -1;
491  memmove(to, to + l, len - l + 1); // we also copy the terminating 0!
492  len -= l;
493  l = 0;
494  }
495  if (l && IsShortName) {
496  if (l < sizeShortVersion) {
497  for (int i = 0; i < l; i++)
498  *shortVersion++ = to[i];
499  sizeShortVersion -= l;
500  }
501  }
502  to += l;
503  len -= l;
504  }
505  *shortVersion = '\0';
506 }
507 
508 Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor) {
509  Descriptor *d=0;
510  switch (domain) {
511  case SI:
513  case CaDescriptorTag:
514  d=new CaDescriptor();
515  break;
518  break;
519  case AVCDescriptorTag:
520  d=new AVCDescriptor();
521  break;
523  d=new NetworkNameDescriptor();
524  break;
526  d=new ServiceListDescriptor();
527  break;
530  break;
533  break;
536  break;
538  d=new BouquetNameDescriptor();
539  break;
541  d=new ServiceDescriptor();
542  break;
544  d=new NVODReferenceDescriptor();
545  break;
548  break;
550  d=new ComponentDescriptor();
551  break;
554  break;
556  d=new SubtitlingDescriptor();
557  break;
560  break;
563  break;
566  break;
569  break;
572  break;
574  d=new ServiceMoveDescriptor();
575  break;
577  d=new FrequencyListDescriptor();
578  break;
581  break;
583  d=new CaIdentifierDescriptor();
584  break;
586  d=new ShortEventDescriptor();
587  break;
589  d=new ExtendedEventDescriptor();
590  break;
593  break;
595  d=new ContentDescriptor();
596  break;
598  d=new ParentalRatingDescriptor();
599  break;
602  d=new TeletextDescriptor();
603  break;
606  break;
609  break;
611  d=new LinkageDescriptor();
612  break;
614  d=new ISO639LanguageDescriptor();
615  break;
616  case PDCDescriptorTag:
617  d=new PDCDescriptor();
618  break;
620  d=new AncillaryDataDescriptor();
621  break;
624  break;
626  d=new ExtensionDescriptor();
627  break;
629  d=new LogicalChannelDescriptor();
630  break;
633  break;
635  d=new RegistrationDescriptor();
636  break;
639  break;
642  break;
643 
644  //note that it is no problem to implement one
645  //of the unimplemented descriptors.
646 
647  //defined in ISO-13818-1
660  case STDDescriptorTag:
661  case IBPDescriptorTag:
662 
663  //defined in ETSI EN 300 468
667  case MocaicDescriptorTag:
677  case AC3DescriptorTag:
678  case DSNGDescriptorTag:
682 
683  //defined in ETSI EN 300 468 v 1.7.1
685  case TVAIdDescriptorTag:
689  case DTSDescriptorTag:
690  case AACDescriptorTag:
691  default:
692  if (!returnUnimplemetedDescriptor)
693  return 0;
694  d=new UnimplementedDescriptor();
695  break;
696  }
697  break;
698  case MHP:
700  // They once again start with 0x00 (see page 234, MHP specification)
703  break;
706  break;
709  break;
712  break;
715  break;
718  break;
719  // 0x05 - 0x0A is unimplemented this library
730  default:
731  if (!returnUnimplemetedDescriptor)
732  return 0;
733  d=new UnimplementedDescriptor();
734  break;
735  }
736  break;
737  case PCIT:
740  d=new ContentDescriptor();
741  break;
743  d=new ShortEventDescriptor();
744  break;
746  d=new ExtendedEventDescriptor();
747  break;
750  break;
751  default:
752  if (!returnUnimplemetedDescriptor)
753  return 0;
754  d=new UnimplementedDescriptor();
755  break;
756  }
757  break;
758  default: ; // unknown domain, nothing to do
759  }
760  d->setData(da);
761  return d;
762 }
763 
764 } //end of namespace
~DescriptorGroup()
Definition: si.c:187
bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode)
Definition: si.c:389
static Descriptor * getDescriptor(CharArray d, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor)
Definition: si.c:508
#define SingleByteLimit
Definition: si.c:291
Section()
Definition: si.h:254
char * getText()
Definition: si.c:222
bool systemCharacterTableIsSingleByte(void)
Definition: si.c:317
bool getCurrentNextIndicator() const
Definition: si.c:80
Descriptor * createDescriptor(int &i, bool returnUnimplemetedDescriptor)
Definition: si.c:159
bool isComplete()
Definition: si.c:215
const char * getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte)
Definition: si.c:354
void Delete()
Definition: si.c:193
bool isCRCValid()
Definition: si.c:61
#define MT(s, m, v)
int getNumberOfDescriptors()
Definition: si.c:170
DescriptorTag
Definition: si.h:51
#define NumEntries(Table)
Definition: si.c:312
u_char descriptor_tag
Definition: headers.h:68
DescriptorTag getDescriptorTag() const
Definition: si.c:100
TableId getTableId() const
Definition: si.c:45
virtual int getLastDescriptorNumber()=0
Definition: descriptor.c:16
int getSectionNumber() const
Definition: si.c:88
static const char * CharacterTables1[]
Definition: si.c:256
virtual int getLength()
Definition: si.c:96
void CheckParse()
Definition: util.c:182
bool checkSize(int offset)
Definition: si.c:37
Definition: si.h:195
static char * OverrideCharacterTable
Definition: si.c:322
virtual int getLength()
Definition: si.c:49
int getTableIdExtension() const
Definition: si.c:72
virtual int getLength()=0
Object()
Definition: si.c:23
bool Add(GroupDescriptor *d)
Definition: si.c:201
void setData(const unsigned char *data, int size, bool doCopy=true)
Definition: si.c:29
void assign(const unsigned char *data, int size, bool doCopy=true)
Definition: util.c:50
static int Utf8CharLen(const char *s)
Definition: si.c:417
virtual int getDescriptorNumber()=0
bool SetSystemCharacterTable(const char *CharacterTable)
Definition: si.c:330
void decodeText(char *buffer, int size)
Definition: si.c:432
bool CheckCRCAndParse()
Definition: si.c:65
DescriptorTagDomain
Definition: si.h:195
int getVersionNumber() const
Definition: si.c:84
int getLastSectionNumber() const
Definition: si.c:92
static const char * SystemCharacterTable
Definition: si.c:314
bool isValid()
Definition: si.h:238
bool checkSize(int offset)
Definition: util.h:63
CharArray data
Definition: si.h:241
Definition: si.h:195
bool SystemCharacterTableIsSingleByte
Definition: si.c:315
TableId
Definition: si.h:23
bool isValid()
Definition: util.h:150
const unsigned char * getData() const
Definition: util.h:51
void SetOverrideCharacterTable(const char *CharacterTable)
Definition: si.c:324
Descriptor * getNext(Iterator &it)
Definition: si.c:112
#define HILO(x)
Definition: util.h:21
DescriptorGroup(bool deleteOnDesctruction=true)
Definition: si.c:181
static const char * CharacterTables2[]
Definition: si.c:293