2003-11-22 17:56:45 +01:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (c) 2003 by Marcel Wiesweg *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
2009-12-06 12:57:45 +01:00
|
|
|
* $Id: si.c 2.1 2009/12/05 16:20:12 kls Exp $
|
2003-12-13 10:43:26 +01:00
|
|
|
* *
|
2003-11-22 17:56:45 +01:00
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "si.h"
|
2007-04-22 14:49:26 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <iconv.h>
|
|
|
|
#include <malloc.h>
|
2008-03-05 17:16:31 +01:00
|
|
|
#include <stdlib.h> // for broadcaster stupidity workaround
|
2007-04-22 14:49:26 +02:00
|
|
|
#include <string.h>
|
2003-11-22 17:56:45 +01:00
|
|
|
#include "descriptor.h"
|
|
|
|
|
|
|
|
namespace SI {
|
|
|
|
|
|
|
|
Object::Object() {
|
|
|
|
}
|
|
|
|
|
|
|
|
Object::Object(CharArray &d) : data(d) {
|
|
|
|
}
|
|
|
|
|
2006-02-18 10:42:55 +01:00
|
|
|
void Object::setData(const unsigned char*d, int size, bool doCopy) {
|
2003-11-22 17:56:45 +01:00
|
|
|
data.assign(d, size, doCopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object::setData(CharArray &d) {
|
|
|
|
data=d;
|
|
|
|
}
|
|
|
|
|
2006-02-18 10:42:55 +01:00
|
|
|
bool Object::checkSize(int offset) {
|
2004-10-16 10:14:19 +02:00
|
|
|
return data.checkSize(offset);
|
|
|
|
}
|
|
|
|
|
2003-11-22 17:56:45 +01:00
|
|
|
Section::Section(const unsigned char *data, bool doCopy) {
|
|
|
|
setData(data, getLength(data), doCopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
TableId Section::getTableId() const {
|
|
|
|
return getTableId(data.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
int Section::getLength() {
|
|
|
|
return getLength(data.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
TableId Section::getTableId(const unsigned char *d) {
|
2003-12-13 10:43:26 +01:00
|
|
|
return (TableId)((const SectionHeader *)d)->table_id;
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int Section::getLength(const unsigned char *d) {
|
2003-12-13 10:43:26 +01:00
|
|
|
return HILO(((const SectionHeader *)d)->section_length)+sizeof(SectionHeader);
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
|
2004-10-16 10:14:19 +02:00
|
|
|
bool CRCSection::isCRCValid() {
|
2003-11-22 17:56:45 +01:00
|
|
|
return CRC32::isValid((const char *)data.getData(), getLength()/*, data.FourBytes(getLength()-4)*/);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CRCSection::CheckCRCAndParse() {
|
2004-10-16 10:14:19 +02:00
|
|
|
if (!isCRCValid())
|
2003-11-22 17:56:45 +01:00
|
|
|
return false;
|
|
|
|
CheckParse();
|
2004-10-16 10:14:19 +02:00
|
|
|
return isValid();
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
|
2004-02-20 13:54:14 +01:00
|
|
|
int NumberedSection::getTableIdExtension() const {
|
|
|
|
return getTableIdExtension(data.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
int NumberedSection::getTableIdExtension(const unsigned char *d) {
|
|
|
|
return HILO(((const ExtendedSectionHeader *)d)->table_id_extension);
|
|
|
|
}
|
|
|
|
|
2003-11-22 17:56:45 +01:00
|
|
|
bool NumberedSection::getCurrentNextIndicator() const {
|
|
|
|
return data.getData<ExtendedSectionHeader>()->current_next_indicator;
|
|
|
|
}
|
|
|
|
|
|
|
|
int NumberedSection::getVersionNumber() const {
|
|
|
|
return data.getData<ExtendedSectionHeader>()->version_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
int NumberedSection::getSectionNumber() const {
|
|
|
|
return data.getData<ExtendedSectionHeader>()->section_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
int NumberedSection::getLastSectionNumber() const {
|
|
|
|
return data.getData<ExtendedSectionHeader>()->last_section_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Descriptor::getLength() {
|
|
|
|
return getLength(data.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
DescriptorTag Descriptor::getDescriptorTag() const {
|
|
|
|
return getDescriptorTag(data.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
int Descriptor::getLength(const unsigned char *d) {
|
|
|
|
return ((const DescriptorHeader*)d)->descriptor_length+sizeof(DescriptorHeader);
|
|
|
|
}
|
|
|
|
|
|
|
|
DescriptorTag Descriptor::getDescriptorTag(const unsigned char *d) {
|
|
|
|
return (DescriptorTag)((const DescriptorHeader*)d)->descriptor_tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
Descriptor *DescriptorLoop::getNext(Iterator &it) {
|
2004-10-16 10:14:19 +02:00
|
|
|
if (isValid() && it.i<getLength()) {
|
2004-03-07 11:13:54 +01:00
|
|
|
return createDescriptor(it.i, true);
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor) {
|
|
|
|
Descriptor *d=0;
|
2005-05-28 14:19:16 +02:00
|
|
|
int len;
|
|
|
|
if (isValid() && it.i<(len=getLength())) {
|
2003-11-22 17:56:45 +01:00
|
|
|
const unsigned char *p=data.getData(it.i);
|
2005-05-28 14:19:16 +02:00
|
|
|
const unsigned char *end=p+len-it.i;
|
2003-11-22 17:56:45 +01:00
|
|
|
while (p < end) {
|
|
|
|
if (Descriptor::getDescriptorTag(p) == tag) {
|
2004-03-07 11:13:54 +01:00
|
|
|
d=createDescriptor(it.i, returnUnimplemetedDescriptor);
|
|
|
|
if (d)
|
|
|
|
break;
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
it.i+=Descriptor::getLength(p);
|
|
|
|
p+=Descriptor::getLength(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2004-03-07 11:13:54 +01:00
|
|
|
Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplementedDescriptor) {
|
2003-11-22 17:56:45 +01:00
|
|
|
Descriptor *d=0;
|
2005-05-28 14:19:16 +02:00
|
|
|
int len;
|
|
|
|
if (isValid() && it.i<(len=getLength())) {
|
2003-11-22 17:56:45 +01:00
|
|
|
const unsigned char *p=data.getData(it.i);
|
2005-05-28 14:19:16 +02:00
|
|
|
const unsigned char *end=p+len-it.i;
|
2003-11-22 17:56:45 +01:00
|
|
|
while (p < end) {
|
|
|
|
for (int u=0; u<arrayLength;u++)
|
|
|
|
if (Descriptor::getDescriptorTag(p) == tags[u]) {
|
2004-03-07 11:13:54 +01:00
|
|
|
d=createDescriptor(it.i, returnUnimplementedDescriptor);
|
2003-11-22 17:56:45 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (d)
|
2004-03-07 11:13:54 +01:00
|
|
|
break; //length is added to it.i by createDescriptor, break here
|
2003-11-22 17:56:45 +01:00
|
|
|
it.i+=Descriptor::getLength(p);
|
|
|
|
p+=Descriptor::getLength(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2004-03-07 11:13:54 +01:00
|
|
|
Descriptor *DescriptorLoop::createDescriptor(int &i, bool returnUnimplemetedDescriptor) {
|
2004-10-16 10:14:19 +02:00
|
|
|
if (!checkSize(Descriptor::getLength(data.getData(i))))
|
|
|
|
return 0;
|
2004-03-07 11:13:54 +01:00
|
|
|
Descriptor *d=Descriptor::getDescriptor(data+i, domain, returnUnimplemetedDescriptor);
|
|
|
|
if (!d)
|
|
|
|
return 0;
|
2003-11-22 17:56:45 +01:00
|
|
|
i+=d->getLength();
|
|
|
|
d->CheckParse();
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2004-03-07 11:13:54 +01:00
|
|
|
int DescriptorLoop::getNumberOfDescriptors() {
|
|
|
|
const unsigned char *p=data.getData();
|
|
|
|
const unsigned char *end=p+getLength();
|
|
|
|
int count=0;
|
|
|
|
while (p < end) {
|
|
|
|
count++;
|
|
|
|
p+=Descriptor::getLength(p);
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2003-11-22 17:56:45 +01:00
|
|
|
DescriptorGroup::DescriptorGroup(bool del) {
|
|
|
|
array=0;
|
|
|
|
length=0;
|
|
|
|
deleteOnDesctruction=del;
|
|
|
|
}
|
|
|
|
|
|
|
|
DescriptorGroup::~DescriptorGroup() {
|
|
|
|
if (deleteOnDesctruction)
|
|
|
|
Delete();
|
|
|
|
delete[] array;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DescriptorGroup::Delete() {
|
|
|
|
for (int i=0;i<length;i++)
|
|
|
|
if (array[i]!=0) {
|
|
|
|
delete array[i];
|
|
|
|
array[i]=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DescriptorGroup::Add(GroupDescriptor *d) {
|
|
|
|
if (!array) {
|
|
|
|
length=d->getLastDescriptorNumber()+1;
|
|
|
|
array=new GroupDescriptor*[length]; //numbering is zero-based
|
|
|
|
for (int i=0;i<length;i++)
|
|
|
|
array[i]=0;
|
|
|
|
} else if (length != d->getLastDescriptorNumber()+1)
|
|
|
|
return; //avoid crash in case of misuse
|
|
|
|
array[d->getDescriptorNumber()]=d;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DescriptorGroup::isComplete() {
|
|
|
|
for (int i=0;i<length;i++)
|
|
|
|
if (array[i]==0)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *String::getText() {
|
2005-05-28 14:19:16 +02:00
|
|
|
int len=getLength();
|
|
|
|
if (len < 0 || len > 4095)
|
2004-06-06 14:53:21 +02:00
|
|
|
return strdup("text error"); // caller will delete it!
|
2007-06-10 13:02:43 +02:00
|
|
|
char *data=new char(len+1); // FIXME If this function is ever actually used, this buffer might
|
|
|
|
// need to be bigger in order to hold the string as UTF-8.
|
|
|
|
// Maybe decodeText should dynamically handle this? kls 2007-06-10
|
2005-05-28 14:19:16 +02:00
|
|
|
decodeText(data, len+1);
|
2003-11-22 17:56:45 +01:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2004-06-06 14:53:21 +02:00
|
|
|
char *String::getText(char *buffer, int size) {
|
2005-05-28 14:19:16 +02:00
|
|
|
int len=getLength();
|
|
|
|
if (len < 0 || len >= size) {
|
2004-06-06 14:53:21 +02:00
|
|
|
strncpy(buffer, "text error", size);
|
|
|
|
buffer[size-1] = 0;
|
2003-11-22 17:56:45 +01:00
|
|
|
return buffer;
|
|
|
|
}
|
2004-06-06 14:53:21 +02:00
|
|
|
decodeText(buffer, size);
|
2003-11-22 17:56:45 +01:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2004-06-06 14:53:21 +02:00
|
|
|
char *String::getText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) {
|
2005-05-28 14:19:16 +02:00
|
|
|
int len=getLength();
|
|
|
|
if (len < 0 || len >= sizeBuffer) {
|
2004-06-06 14:53:21 +02:00
|
|
|
strncpy(buffer, "text error", sizeBuffer);
|
|
|
|
buffer[sizeBuffer-1] = 0;
|
|
|
|
*shortVersion = 0;
|
2004-03-07 11:13:54 +01:00
|
|
|
return buffer;
|
|
|
|
}
|
2004-06-06 14:53:21 +02:00
|
|
|
decodeText(buffer, shortVersion, sizeBuffer, sizeShortVersion);
|
2004-03-07 11:13:54 +01:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2007-04-22 14:49:26 +02:00
|
|
|
static const char *CharacterTables1[] = {
|
2007-06-15 13:25:35 +02:00
|
|
|
NULL, // 0x00
|
|
|
|
"ISO-8859-5", // 0x01
|
|
|
|
"ISO-8859-6", // 0x02
|
|
|
|
"ISO-8859-7", // 0x03
|
|
|
|
"ISO-8859-8", // 0x04
|
|
|
|
"ISO-8859-9", // 0x05
|
|
|
|
"ISO-8859-10", // 0x06
|
|
|
|
"ISO-8859-11", // 0x07
|
|
|
|
"ISO-8859-12", // 0x08
|
|
|
|
"ISO-8859-13", // 0x09
|
|
|
|
"ISO-8859-14", // 0x0A
|
|
|
|
"ISO-8859-15", // 0x0B
|
|
|
|
NULL, // 0x0C
|
|
|
|
NULL, // 0x0D
|
|
|
|
NULL, // 0x0E
|
|
|
|
NULL, // 0x0F
|
|
|
|
NULL, // 0x10
|
|
|
|
"UTF-16", // 0x11
|
|
|
|
"EUC-KR", // 0x12
|
|
|
|
"GB2312", // 0x13
|
|
|
|
"GBK", // 0x14
|
|
|
|
"UTF-8", // 0x15
|
|
|
|
NULL, // 0x16
|
|
|
|
NULL, // 0x17
|
|
|
|
NULL, // 0x18
|
|
|
|
NULL, // 0x19
|
|
|
|
NULL, // 0x1A
|
|
|
|
NULL, // 0x1B
|
|
|
|
NULL, // 0x1C
|
|
|
|
NULL, // 0x1D
|
|
|
|
NULL, // 0x1E
|
|
|
|
NULL, // 0x1F
|
2007-04-22 14:49:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#define SingleByteLimit 0x0B
|
|
|
|
|
|
|
|
static const char *CharacterTables2[] = {
|
2007-07-21 13:49:48 +02:00
|
|
|
NULL, // 0x00
|
2007-06-15 13:25:35 +02:00
|
|
|
"ISO-8859-1", // 0x01
|
|
|
|
"ISO-8859-2", // 0x02
|
|
|
|
"ISO-8859-3", // 0x03
|
|
|
|
"ISO-8859-4", // 0x04
|
|
|
|
"ISO-8859-5", // 0x05
|
|
|
|
"ISO-8859-6", // 0x06
|
|
|
|
"ISO-8859-7", // 0x07
|
|
|
|
"ISO-8859-8", // 0x08
|
|
|
|
"ISO-8859-9", // 0x09
|
|
|
|
"ISO-8859-10", // 0x0A
|
|
|
|
"ISO-8859-11", // 0x0B
|
2007-07-21 13:49:48 +02:00
|
|
|
NULL, // 0x0C
|
2007-06-15 13:25:35 +02:00
|
|
|
"ISO-8859-13", // 0x0D
|
|
|
|
"ISO-8859-14", // 0x0E
|
|
|
|
"ISO-8859-15", // 0x0F
|
2007-04-22 14:49:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#define NumEntries(Table) (sizeof(Table) / sizeof(char *))
|
|
|
|
|
|
|
|
static const char *SystemCharacterTable = NULL;
|
|
|
|
bool SystemCharacterTableIsSingleByte = true;
|
|
|
|
|
|
|
|
bool SetSystemCharacterTable(const char *CharacterTable) {
|
|
|
|
if (CharacterTable) {
|
|
|
|
for (unsigned int i = 0; i < NumEntries(CharacterTables1); i++) {
|
|
|
|
if (CharacterTables1[i] && strcasecmp(CharacterTable, CharacterTables1[i]) == 0) {
|
|
|
|
SystemCharacterTable = CharacterTables1[i];
|
|
|
|
SystemCharacterTableIsSingleByte = i <= SingleByteLimit;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (unsigned int i = 0; i < NumEntries(CharacterTables2); i++) {
|
|
|
|
if (CharacterTables2[i] && strcasecmp(CharacterTable, CharacterTables2[i]) == 0) {
|
|
|
|
SystemCharacterTable = CharacterTables2[i];
|
|
|
|
SystemCharacterTableIsSingleByte = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SystemCharacterTable = NULL;
|
|
|
|
SystemCharacterTableIsSingleByte = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determines the character table used in the given buffer and returns
|
|
|
|
// a string indicating that table. If no table can be determined, the
|
|
|
|
// default ISO6937 is returned. If a table can be determined, the buffer
|
|
|
|
// and length are adjusted accordingly.
|
|
|
|
static const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte = NULL) {
|
|
|
|
const char *cs = "ISO6937";
|
2008-03-05 17:16:31 +01:00
|
|
|
// Workaround for broadcaster stupidity: according to
|
2008-03-01 12:06:27 +01:00
|
|
|
// "ETSI EN 300 468" the default character set is ISO6937. But unfortunately some
|
|
|
|
// broadcasters actually use ISO-8859-9, but fail to correctly announce that.
|
2008-03-05 17:16:31 +01:00
|
|
|
static const char *CharsetOverride = getenv("VDR_CHARSET_OVERRIDE");
|
|
|
|
if (CharsetOverride)
|
|
|
|
cs = CharsetOverride;
|
2007-04-22 14:49:26 +02:00
|
|
|
if (isSingleByte)
|
|
|
|
*isSingleByte = false;
|
|
|
|
if (length <= 0)
|
|
|
|
return cs;
|
|
|
|
unsigned int tag = buffer[0];
|
|
|
|
if (tag >= 0x20)
|
|
|
|
return cs;
|
|
|
|
if (tag == 0x10) {
|
|
|
|
if (length >= 3) {
|
|
|
|
tag = (buffer[1] << 8) | buffer[2];
|
|
|
|
if (tag < NumEntries(CharacterTables2) && CharacterTables2[tag]) {
|
|
|
|
buffer += 3;
|
|
|
|
length -= 3;
|
|
|
|
if (isSingleByte)
|
|
|
|
*isSingleByte = true;
|
|
|
|
return CharacterTables2[tag];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (tag < NumEntries(CharacterTables1) && CharacterTables1[tag]) {
|
|
|
|
buffer += 1;
|
|
|
|
length -= 1;
|
|
|
|
if (isSingleByte)
|
|
|
|
*isSingleByte = tag <= SingleByteLimit;
|
|
|
|
return CharacterTables1[tag];
|
|
|
|
}
|
|
|
|
return cs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode)
|
|
|
|
{
|
|
|
|
if (SystemCharacterTable) {
|
|
|
|
iconv_t cd = iconv_open(SystemCharacterTable, fromCode);
|
2007-05-28 10:22:42 +02:00
|
|
|
if (cd != (iconv_t)-1) {
|
2007-04-22 14:49:26 +02:00
|
|
|
char *fromPtr = (char *)from;
|
|
|
|
while (fromLength > 0 && toLength > 1) {
|
|
|
|
if (iconv(cd, &fromPtr, &fromLength, &to, &toLength) == size_t(-1)) {
|
|
|
|
if (errno == EILSEQ) {
|
|
|
|
// A character can't be converted, so mark it with '?' and proceed:
|
|
|
|
fromPtr++;
|
|
|
|
fromLength--;
|
|
|
|
*to++ = '?';
|
|
|
|
toLength--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*to = 0;
|
|
|
|
iconv_close(cd);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// originally from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de>
|
2004-06-06 14:53:21 +02:00
|
|
|
void String::decodeText(char *buffer, int size) {
|
2003-11-22 17:56:45 +01:00
|
|
|
const unsigned char *from=data.getData(0);
|
|
|
|
char *to=buffer;
|
2005-05-28 14:19:16 +02:00
|
|
|
int len=getLength();
|
2007-04-22 14:49:26 +02:00
|
|
|
if (len <= 0) {
|
|
|
|
*to = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bool singleByte;
|
|
|
|
const char *cs = getCharacterTable(from, len, &singleByte);
|
2007-06-10 13:02:43 +02:00
|
|
|
// FIXME Need to make this UTF-8 aware (different control codes).
|
|
|
|
// However, there's yet to be found a broadcaster that actually
|
|
|
|
// uses UTF-8 for the SI data... (kls 2007-06-10)
|
2005-05-28 14:19:16 +02:00
|
|
|
for (int i = 0; i < len; i++) {
|
2003-11-22 17:56:45 +01:00
|
|
|
if (*from == 0)
|
|
|
|
break;
|
2003-12-13 10:43:26 +01:00
|
|
|
if ( ((' ' <= *from) && (*from <= '~'))
|
2003-11-22 17:56:45 +01:00
|
|
|
|| (*from == '\n')
|
2004-01-05 11:04:17 +01:00
|
|
|
|| (0xA0 <= *from)
|
2003-11-22 17:56:45 +01:00
|
|
|
)
|
|
|
|
*to++ = *from;
|
|
|
|
else if (*from == 0x8A)
|
|
|
|
*to++ = '\n';
|
2004-03-07 11:13:54 +01:00
|
|
|
from++;
|
2004-06-06 14:53:21 +02:00
|
|
|
if (to - buffer >= size - 1)
|
|
|
|
break;
|
2004-03-07 11:13:54 +01:00
|
|
|
}
|
|
|
|
*to = '\0';
|
2007-04-22 14:49:26 +02:00
|
|
|
if (!singleByte || !SystemCharacterTableIsSingleByte) {
|
|
|
|
char convBuffer[size];
|
|
|
|
if (convertCharacterTable(buffer, strlen(buffer), convBuffer, sizeof(convBuffer), cs))
|
|
|
|
strncpy(buffer, convBuffer, strlen(convBuffer) + 1);
|
|
|
|
}
|
2004-03-07 11:13:54 +01:00
|
|
|
}
|
|
|
|
|
2004-06-06 14:53:21 +02:00
|
|
|
void String::decodeText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) {
|
2004-03-07 11:13:54 +01:00
|
|
|
const unsigned char *from=data.getData(0);
|
|
|
|
char *to=buffer;
|
|
|
|
char *toShort=shortVersion;
|
|
|
|
int IsShortName=0;
|
2005-05-28 14:19:16 +02:00
|
|
|
int len=getLength();
|
2007-04-22 14:49:26 +02:00
|
|
|
if (len <= 0) {
|
|
|
|
*to = '\0';
|
|
|
|
*toShort = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bool singleByte;
|
|
|
|
const char *cs = getCharacterTable(from, len, &singleByte);
|
2007-06-10 13:02:43 +02:00
|
|
|
// FIXME Need to make this UTF-8 aware (different control codes).
|
|
|
|
// However, there's yet to be found a broadcaster that actually
|
|
|
|
// uses UTF-8 for the SI data... (kls 2007-06-10)
|
2005-05-28 14:19:16 +02:00
|
|
|
for (int i = 0; i < len; i++) {
|
2004-03-07 11:13:54 +01:00
|
|
|
if ( ((' ' <= *from) && (*from <= '~'))
|
|
|
|
|| (*from == '\n')
|
|
|
|
|| (0xA0 <= *from)
|
|
|
|
)
|
|
|
|
{
|
2004-01-04 14:26:53 +01:00
|
|
|
*to++ = *from;
|
2004-03-07 11:13:54 +01:00
|
|
|
if (IsShortName)
|
|
|
|
*toShort++ = *from;
|
|
|
|
}
|
|
|
|
else if (*from == 0x8A)
|
|
|
|
*to++ = '\n';
|
|
|
|
else if (*from == 0x86)
|
|
|
|
IsShortName++;
|
|
|
|
else if (*from == 0x87)
|
|
|
|
IsShortName--;
|
2005-05-28 14:19:16 +02:00
|
|
|
else if (*from == 0)
|
|
|
|
break;
|
2003-11-22 17:56:45 +01:00
|
|
|
from++;
|
2004-06-06 14:53:21 +02:00
|
|
|
if (to - buffer >= sizeBuffer - 1 || toShort - shortVersion >= sizeShortVersion - 1)
|
|
|
|
break;
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
*to = '\0';
|
2004-03-07 11:13:54 +01:00
|
|
|
*toShort = '\0';
|
2007-04-22 14:49:26 +02:00
|
|
|
if (!singleByte || !SystemCharacterTableIsSingleByte) {
|
|
|
|
char convBuffer[sizeBuffer];
|
|
|
|
if (convertCharacterTable(buffer, strlen(buffer), convBuffer, sizeof(convBuffer), cs))
|
|
|
|
strncpy(buffer, convBuffer, strlen(convBuffer) + 1);
|
|
|
|
char convShortVersion[sizeShortVersion];
|
|
|
|
if (convertCharacterTable(shortVersion, strlen(shortVersion), convShortVersion, sizeof(convShortVersion), cs))
|
|
|
|
strncpy(shortVersion, convShortVersion, strlen(convShortVersion) + 1);
|
|
|
|
}
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
|
2004-03-07 11:13:54 +01:00
|
|
|
Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor) {
|
2003-11-22 17:56:45 +01:00
|
|
|
Descriptor *d=0;
|
|
|
|
switch (domain) {
|
|
|
|
case SI:
|
|
|
|
switch ((DescriptorTag)da.getData<DescriptorHeader>()->descriptor_tag) {
|
|
|
|
case CaDescriptorTag:
|
|
|
|
d=new CaDescriptor();
|
|
|
|
break;
|
|
|
|
case CarouselIdentifierDescriptorTag:
|
|
|
|
d=new CarouselIdentifierDescriptor();
|
|
|
|
break;
|
|
|
|
case NetworkNameDescriptorTag:
|
|
|
|
d=new NetworkNameDescriptor();
|
|
|
|
break;
|
|
|
|
case ServiceListDescriptorTag:
|
|
|
|
d=new ServiceListDescriptor();
|
|
|
|
break;
|
|
|
|
case SatelliteDeliverySystemDescriptorTag:
|
|
|
|
d=new SatelliteDeliverySystemDescriptor();
|
|
|
|
break;
|
|
|
|
case CableDeliverySystemDescriptorTag:
|
|
|
|
d=new CableDeliverySystemDescriptor();
|
|
|
|
break;
|
|
|
|
case TerrestrialDeliverySystemDescriptorTag:
|
|
|
|
d=new TerrestrialDeliverySystemDescriptor();
|
|
|
|
break;
|
|
|
|
case BouquetNameDescriptorTag:
|
|
|
|
d=new BouquetNameDescriptor();
|
|
|
|
break;
|
|
|
|
case ServiceDescriptorTag:
|
|
|
|
d=new ServiceDescriptor();
|
|
|
|
break;
|
|
|
|
case NVODReferenceDescriptorTag:
|
|
|
|
d=new NVODReferenceDescriptor();
|
|
|
|
break;
|
|
|
|
case TimeShiftedServiceDescriptorTag:
|
|
|
|
d=new TimeShiftedServiceDescriptor();
|
|
|
|
break;
|
|
|
|
case ComponentDescriptorTag:
|
|
|
|
d=new ComponentDescriptor();
|
|
|
|
break;
|
|
|
|
case StreamIdentifierDescriptorTag:
|
|
|
|
d=new StreamIdentifierDescriptor();
|
|
|
|
break;
|
|
|
|
case SubtitlingDescriptorTag:
|
|
|
|
d=new SubtitlingDescriptor();
|
|
|
|
break;
|
|
|
|
case MultilingualNetworkNameDescriptorTag:
|
|
|
|
d=new MultilingualNetworkNameDescriptor();
|
|
|
|
break;
|
|
|
|
case MultilingualBouquetNameDescriptorTag:
|
|
|
|
d=new MultilingualBouquetNameDescriptor();
|
|
|
|
break;
|
|
|
|
case MultilingualServiceNameDescriptorTag:
|
|
|
|
d=new MultilingualServiceNameDescriptor();
|
|
|
|
break;
|
|
|
|
case MultilingualComponentDescriptorTag:
|
|
|
|
d=new MultilingualComponentDescriptor();
|
|
|
|
break;
|
2006-04-14 10:59:03 +02:00
|
|
|
case PrivateDataSpecifierDescriptorTag:
|
|
|
|
d=new PrivateDataSpecifierDescriptor();
|
|
|
|
break;
|
2003-11-22 17:56:45 +01:00
|
|
|
case ServiceMoveDescriptorTag:
|
|
|
|
d=new ServiceMoveDescriptor();
|
|
|
|
break;
|
|
|
|
case FrequencyListDescriptorTag:
|
|
|
|
d=new FrequencyListDescriptor();
|
|
|
|
break;
|
|
|
|
case ServiceIdentifierDescriptorTag:
|
|
|
|
d=new ServiceIdentifierDescriptor();
|
|
|
|
break;
|
|
|
|
case CaIdentifierDescriptorTag:
|
|
|
|
d=new CaIdentifierDescriptor();
|
2003-12-13 10:43:26 +01:00
|
|
|
break;
|
2003-11-22 17:56:45 +01:00
|
|
|
case ShortEventDescriptorTag:
|
|
|
|
d=new ShortEventDescriptor();
|
|
|
|
break;
|
|
|
|
case ExtendedEventDescriptorTag:
|
|
|
|
d=new ExtendedEventDescriptor();
|
|
|
|
break;
|
|
|
|
case TimeShiftedEventDescriptorTag:
|
|
|
|
d=new TimeShiftedEventDescriptor();
|
|
|
|
break;
|
|
|
|
case ContentDescriptorTag:
|
|
|
|
d=new ContentDescriptor();
|
|
|
|
break;
|
|
|
|
case ParentalRatingDescriptorTag:
|
|
|
|
d=new ParentalRatingDescriptor();
|
|
|
|
break;
|
2006-04-14 10:59:03 +02:00
|
|
|
case TeletextDescriptorTag:
|
|
|
|
case VBITeletextDescriptorTag:
|
|
|
|
d=new TeletextDescriptor();
|
|
|
|
break;
|
2003-11-22 17:56:45 +01:00
|
|
|
case ApplicationSignallingDescriptorTag:
|
|
|
|
d=new ApplicationSignallingDescriptor();
|
|
|
|
break;
|
2006-04-14 10:59:03 +02:00
|
|
|
case LocalTimeOffsetDescriptorTag:
|
|
|
|
d=new LocalTimeOffsetDescriptor();
|
|
|
|
break;
|
2004-01-12 22:19:34 +01:00
|
|
|
case LinkageDescriptorTag:
|
|
|
|
d=new LinkageDescriptor();
|
|
|
|
break;
|
2004-01-24 14:49:51 +01:00
|
|
|
case ISO639LanguageDescriptorTag:
|
|
|
|
d=new ISO639LanguageDescriptor();
|
|
|
|
break;
|
2004-02-22 13:08:04 +01:00
|
|
|
case PDCDescriptorTag:
|
|
|
|
d=new PDCDescriptor();
|
|
|
|
break;
|
2006-04-14 10:59:03 +02:00
|
|
|
case AncillaryDataDescriptorTag:
|
|
|
|
d=new AncillaryDataDescriptor();
|
|
|
|
break;
|
2007-02-03 12:13:08 +01:00
|
|
|
case S2SatelliteDeliverySystemDescriptorTag:
|
|
|
|
d=new S2SatelliteDeliverySystemDescriptor();
|
|
|
|
break;
|
|
|
|
case ExtensionDescriptorTag:
|
|
|
|
d=new ExtensionDescriptor();
|
|
|
|
break;
|
2003-12-13 10:43:26 +01:00
|
|
|
|
2003-11-22 17:56:45 +01:00
|
|
|
//note that it is no problem to implement one
|
|
|
|
//of the unimplemented descriptors.
|
2003-12-13 10:43:26 +01:00
|
|
|
|
2003-11-22 17:56:45 +01:00
|
|
|
//defined in ISO-13818-1
|
|
|
|
case VideoStreamDescriptorTag:
|
|
|
|
case AudioStreamDescriptorTag:
|
|
|
|
case HierarchyDescriptorTag:
|
|
|
|
case RegistrationDescriptorTag:
|
|
|
|
case DataStreamAlignmentDescriptorTag:
|
|
|
|
case TargetBackgroundGridDescriptorTag:
|
|
|
|
case VideoWindowDescriptorTag:
|
|
|
|
case SystemClockDescriptorTag:
|
|
|
|
case MultiplexBufferUtilizationDescriptorTag:
|
|
|
|
case CopyrightDescriptorTag:
|
|
|
|
case MaximumBitrateDescriptorTag:
|
|
|
|
case PrivateDataIndicatorDescriptorTag:
|
|
|
|
case SmoothingBufferDescriptorTag:
|
|
|
|
case STDDescriptorTag:
|
|
|
|
case IBPDescriptorTag:
|
2003-12-13 10:43:26 +01:00
|
|
|
|
2003-11-22 17:56:45 +01:00
|
|
|
//defined in ETSI EN 300 468
|
|
|
|
case StuffingDescriptorTag:
|
|
|
|
case VBIDataDescriptorTag:
|
|
|
|
case CountryAvailabilityDescriptorTag:
|
|
|
|
case MocaicDescriptorTag:
|
|
|
|
case TelephoneDescriptorTag:
|
|
|
|
case CellListDescriptorTag:
|
|
|
|
case CellFrequencyLinkDescriptorTag:
|
|
|
|
case ServiceAvailabilityDescriptorTag:
|
|
|
|
case ShortSmoothingBufferDescriptorTag:
|
|
|
|
case PartialTransportStreamDescriptorTag:
|
|
|
|
case DataBroadcastDescriptorTag:
|
|
|
|
case DataBroadcastIdDescriptorTag:
|
2007-02-03 12:13:08 +01:00
|
|
|
case ScramblingDescriptorTag:
|
2003-11-22 17:56:45 +01:00
|
|
|
case AC3DescriptorTag:
|
|
|
|
case DSNGDescriptorTag:
|
2003-12-13 10:43:26 +01:00
|
|
|
case AnnouncementSupportDescriptorTag:
|
2003-11-22 17:56:45 +01:00
|
|
|
case AdaptationFieldDataDescriptorTag:
|
|
|
|
case TransportStreamDescriptorTag:
|
2007-02-03 12:13:08 +01:00
|
|
|
|
|
|
|
//defined in ETSI EN 300 468 v 1.7.1
|
|
|
|
case DefaultAuthorityDescriptorTag:
|
|
|
|
case RelatedContentDescriptorTag:
|
|
|
|
case TVAIdDescriptorTag:
|
|
|
|
case ContentIdentifierDescriptorTag:
|
|
|
|
case TimeSliceFecIdentifierDescriptorTag:
|
|
|
|
case ECMRepetitionRateDescriptorTag:
|
|
|
|
case EnhancedAC3DescriptorTag:
|
|
|
|
case DTSDescriptorTag:
|
|
|
|
case AACDescriptorTag:
|
2003-11-22 17:56:45 +01:00
|
|
|
default:
|
2004-03-07 11:13:54 +01:00
|
|
|
if (!returnUnimplemetedDescriptor)
|
|
|
|
return 0;
|
2003-11-22 17:56:45 +01:00
|
|
|
d=new UnimplementedDescriptor();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MHP:
|
|
|
|
switch ((DescriptorTag)da.getData<DescriptorHeader>()->descriptor_tag) {
|
|
|
|
// They once again start with 0x00 (see page 234, MHP specification)
|
|
|
|
case MHP_ApplicationDescriptorTag:
|
|
|
|
d=new MHP_ApplicationDescriptor();
|
|
|
|
break;
|
|
|
|
case MHP_ApplicationNameDescriptorTag:
|
|
|
|
d=new MHP_ApplicationNameDescriptor();
|
|
|
|
break;
|
|
|
|
case MHP_TransportProtocolDescriptorTag:
|
|
|
|
d=new MHP_TransportProtocolDescriptor();
|
|
|
|
break;
|
|
|
|
case MHP_DVBJApplicationDescriptorTag:
|
|
|
|
d=new MHP_DVBJApplicationDescriptor();
|
|
|
|
break;
|
|
|
|
case MHP_DVBJApplicationLocationDescriptorTag:
|
|
|
|
d=new MHP_DVBJApplicationLocationDescriptor();
|
|
|
|
break;
|
|
|
|
// 0x05 - 0x0A is unimplemented this library
|
|
|
|
case MHP_ExternalApplicationAuthorisationDescriptorTag:
|
|
|
|
case MHP_IPv4RoutingDescriptorTag:
|
|
|
|
case MHP_IPv6RoutingDescriptorTag:
|
|
|
|
case MHP_DVBHTMLApplicationDescriptorTag:
|
|
|
|
case MHP_DVBHTMLApplicationLocationDescriptorTag:
|
|
|
|
case MHP_DVBHTMLApplicationBoundaryDescriptorTag:
|
|
|
|
case MHP_ApplicationIconsDescriptorTag:
|
|
|
|
case MHP_PrefetchDescriptorTag:
|
|
|
|
case MHP_DelegatedApplicationDescriptorTag:
|
|
|
|
case MHP_ApplicationStorageDescriptorTag:
|
|
|
|
default:
|
2004-03-07 11:13:54 +01:00
|
|
|
if (!returnUnimplemetedDescriptor)
|
|
|
|
return 0;
|
2003-11-22 17:56:45 +01:00
|
|
|
d=new UnimplementedDescriptor();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2006-04-14 10:59:03 +02:00
|
|
|
case PCIT:
|
|
|
|
switch ((DescriptorTag)da.getData<DescriptorHeader>()->descriptor_tag) {
|
|
|
|
case ContentDescriptorTag:
|
|
|
|
d=new ContentDescriptor();
|
|
|
|
break;
|
|
|
|
case ShortEventDescriptorTag:
|
|
|
|
d=new ShortEventDescriptor();
|
|
|
|
break;
|
|
|
|
case ExtendedEventDescriptorTag:
|
|
|
|
d=new ExtendedEventDescriptor();
|
|
|
|
break;
|
|
|
|
case PremiereContentTransmissionDescriptorTag:
|
|
|
|
d=new PremiereContentTransmissionDescriptor();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (!returnUnimplemetedDescriptor)
|
|
|
|
return 0;
|
|
|
|
d=new UnimplementedDescriptor();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2009-12-06 12:57:45 +01:00
|
|
|
default: ; // unknown domain, nothing to do
|
2003-11-22 17:56:45 +01:00
|
|
|
}
|
|
|
|
d->setData(da);
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
} //end of namespace
|