You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

289 lines
6.6 KiB

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include "lint.h"
#include "xconv.h"
#define STRING(addr, x, len) hmt->x = (char *)strip_string(hmt->bin + addr)
#define LE32(addr, x) hmt->x = read_uint32(hmt->bin + addr, 1)
#define LE16(addr, x) hmt->x = read_uint16(hmt->bin + addr, 1)
#define LE8(addr, x) hmt->x = hmt->bin[addr] & 0xff
#define PTR32(addr, x) hmt->x = (uint32_t *)(hmt->bin + addr);
/* ETSI EN 300 468 Annex A.2 */
uint8_t *
strip_string(uint8_t *str)
{
if (*str >= 0x20)
return str;
if (*str == 0x10)
{
size_t len = strlen((char *) str);
if (len > 3 && str[1] == 'i' && str[2] == '7')
{
len = len * 2 + 8;
char *dst = malloc(len);
if (dst)
{
if (xconv((char *) (str + 3), dst, len))
return (uint8_t *) dst;
else
{
free(dst);
return str + 3;
}
}
}
return (uint8_t *) "";
}
if (*str == 0x1f)
return str + 2;
return str + 1;
}
void
parse_hmt(struct hmt *hmt)
{
STRING( HMT_FOLDER, directory, HMT_FOLDER_LEN);
uint8_t *p = hmt->bin + HMT_FILENAME;
if (!p[0] || (p[0] == p[1]))
++p;
hmt->filename = (char *) strip_string(p);
LE32( HMT_RECORDING_START, start);
LE32( HMT_RECORDING_END, end);
LE16( HMT_STORED_DURATION, duration);
LE8( HMT_RECSTATUS, recstatus);
LE8( HMT_FLAGS1, flags1);
LE8( HMT_FLAGS2, flags2);
LE8( HMT_FAILREASON, failreason);
LE32( HMT_PLAYED_TIME, resume);
LE16( HMT_BOOKMARKS_CNT, num_bookmarks);
STRING( HMT_TITLE, mediatitle, HMT_TITLE_LEN);
PTR32( HMT_BOOKMARKS, bookmarks);
LE8( HMT_FLAGS3, flags3);
LE8( HMT_GUIDETYPE, guidance_type);
LE8( HMT_GUIDEMODE, guidance_mode);
STRING( HMT_GUIDANCE, guidance, HMT_GUIDANCE_LEN + 1);
LE8( HMT_COPYCOUNT, copycount);
LE16( HMT_TZOFFSET, tzoffset);
LE32( HMT_CHANNEL_NUM, lcn);
LE8( HMT_RECTYPE, type);
STRING( HMT_CHANNEL_NAME, channel, HMT_CHANNEL_NAME_LEN + 1);
LE16( HMT_SID, service_id);
LE16( HMT_TSID, tsid);
LE16( HMT_ONID, onid);
LE16( HMT_PMTPID, pmt_pid);
LE16( HMT_VIDEOPID, video_pid);
// LE8( HMT_HDFLAG, definition);
LE8( HMT_HDFLAG2, definition);
LE16( HMT_AUDIOPID, audio_pid);
LE32( HMT_SCHEDULED_START, schedstart);
LE32( HMT_SCHEDULED_DURATION, scheddur);
LE8( HMT_GENRE, genre);
STRING( HMT_ITITLE, title, HMT_ITITLE_LEN + 3);
STRING( HMT_SYNOPSIS, synopsis, HMT_SYNOPSIS + 3);
LE16( HMT_EVENTID, event_id);
LE8( HMT_SHRUNK, xflags1);
LE8( HMT_DEDUPED, xflags2);
LE8( HMT_DETECTADS, xflags3);
LE8( HMT_SERIES, series);
LE8( HMT_EPISODE, episode);
LE8( HMT_EPISODETOT, episodetot);
}
int
hmt_is(struct hmt *hmt, enum hmt_attribute attr)
{
switch (attr)
{
case HMTA_ENCRYPTED:
return hmt->flags2 & HMT_FLAGS2_ENCRYPTED;
case HMTA_THUMBNAIL:
return hmt->flags2 & HMT_FLAGS2_THUMBNAIL;
case HMTA_GHOST:
return hmt->flags2 & HMT_FLAGS2_GHOST;
case HMTA_LOCKED:
return hmt->flags1 & HMT_FLAGS1_LOCKED;
case HMTA_NEW:
return !(hmt->flags1 & HMT_FLAGS1_NEW);
case HMTA_ENCFLAGGED:
return hmt->flags3 != HMT_FLAGS3_UNPROTECTED;
case HMTA_UNLIMITEDCOPY:
return !(hmt->flags3 & HMT_FLAGS3_PROTECTED_COPY_LIMITED);
case HMTA_SHRUNK:
return hmt->xflags1 == 'E';
case HMTA_DEDUPED:
return hmt->xflags2 == 'N';
case HMTA_DETECTADS:
return hmt->xflags3 == 'G';
case HMTA_RADIO:
return hmt->type == HMT_RECTYPE_RADIO;
default:
fprintf(stderr, "Unhandled hmt_is, %d\n", attr);
break;
}
return 0;
}
char *
hmt_flags(struct hmt *hmt)
{
static char buf[0x400];
int g;
*buf = '\0';
if (hmt->definition == DEF_HD)
strcat(buf, "HD,");
else
strcat(buf, "SD,");
if (hmt_is(hmt, HMTA_LOCKED))
strcat(buf, "Locked,");
if (hmt_is(hmt, HMTA_NEW))
strcat(buf, "New,");
if (hmt_is(hmt, HMTA_UNLIMITEDCOPY))
strcat(buf, "Unlimited Copies,");
if (hmt_is(hmt, HMTA_ENCFLAGGED))
strcat(buf, "Encrypted,");
if ((g = guidance(hmt)) == 2)
strcat(buf, "GGuidance,");
else if (g == 1)
strcat(buf, "Guidance,");
if (hmt_is(hmt, HMTA_ENCRYPTED))
strcat(buf, "ODEncrypted,");
if (hmt_is(hmt, HMTA_THUMBNAIL))
strcat(buf, "Thumbnail,");
if (hmt_is(hmt, HMTA_SHRUNK))
strcat(buf, "Shrunk,");
if (hmt_is(hmt, HMTA_DEDUPED))
strcat(buf, "Deduped,");
if (hmt_is(hmt, HMTA_DETECTADS))
strcat(buf, "Addetection,");
if (hmt_is(hmt, HMTA_RADIO))
strcat(buf, "Radio,");
if (hmt_is(hmt, HMTA_GHOST))
strcat(buf, "Ghost,");
return buf;
}
struct {
unsigned char genre;
char *text;
} genretab[] = {
{ 0x00, "Unclassified" },
{ 0x10, "Film" },
{ 0x20, "News & Factual" },
{ 0x30, "Entertainment" },
{ 0x40, "Sport" },
{ 0x50, "Children" },
{ 0x60, "Entertainment" },
{ 0x70, "News & Factual" },
{ 0x80, "News & Factual" },
{ 0x90, "Education" },
{ 0xa0, "Lifestyle" },
{ 0xf0, "Drama" },
{ 0, NULL },
};
const char *
genredescr(unsigned char b)
{
int i;
for (i = 0; genretab[i].text; i++)
if (b == genretab[i].genre)
return genretab[i].text;
return "Unknown";
}
unsigned char
genrecode(char *s)
{
int i;
for (i = 0; genretab[i].text; i++)
if (!strncasecmp(genretab[i].text, s, strlen(s)))
return genretab[i].genre;
return 0;
}
const char *
recordingstatus(struct hmt *hmt)
{
switch (hmt->recstatus)
{
case 0: return "Zero length";
case 1: return "Loss of power";
case 2: return "Valid";
case 3: return "Scrambled";
case 4: return "Failed";
default: break;
}
return "Unknown";
}
const char *
failurereason(struct hmt *hmt)
{
switch (hmt->failreason)
{
case 0: return "OK";
case 1: return "Failed: Disk was full";
case 8:
case 2: return "Failed: Conflicted with another recording";
case 3: return "Failed: Maximum number of files per folder";
case 4: return "Recording less than 30 seconds";
case 5: return "Failed: Lack of signal";
case 13: return "Incomplete: Disk was full";
case 15: return "Failed: No storage device detected";
case 16: return "Incomplete: USB storage device was removed";
case 17: return "Failed: Appears not to have been broadcast";
case 19: return "Failed: Conflicted with a higher priority recording";
case 20: return "Failed: Unable to track";
default: break;
}
return "Unknown";
}
int
guidance(struct hmt *hmt)
{
#if 0
printf("GUIDANCE TYPE/MODE: %d/%d\n",
hmt->guidance_type, hmt->guidance_mode);
#endif
switch (hmt->guidance_type)
{
case 1:
switch (hmt->guidance_mode)
{
case 0:
/* General guidance */
return 2;
default:
/* Adult content */
return 1;
}
break;
default:
switch (hmt->guidance_mode)
{
case 0:
/* No guidance */
return 0;
default:
/* Adult content */
return 1;
}
break;
}
}