hmt/hmt.c

263 lines
5.6 KiB
C

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <strings.h>
#include <time.h>
#include "lint.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)
return str + 3;
if (*str == 0x1f)
return str + 2;
return str + 1;
}
void
parse_hmt(struct hmt *hmt)
{
STRING( 0x80, directory, 254);
STRING( 0x17f, filename, 256);
LE32( 0x280, start);
LE32( 0x284, end);
LE16( 0x288, duration);
LE8( 0x28c, recstatus);
LE8( 0x28d, flags1);
LE8( 0x28e, flags2);
LE8( 0x290, failreason);
LE32( 0x294, resume);
LE16( 0x298, num_bookmarks);
STRING( 0x29a, mediatitle, 48);
PTR32( 0x31c, bookmarks);
LE8( 0x3dc, flags3);
LE8( 0x3e0, guidance_type);
LE8( 0x3e1, guidance_mode);
STRING( 0x3e2, guidance, 75);
LE8( 0x431, copycount);
LE16( 0x434, tzoffset);
LE32( 0x458, lcn);
LE8( 0x4b8, type);
STRING( 0x45c, channel, 43);
LE16( 0x488, service_id);
LE16( 0x48a, tsid);
LE16( 0x48c, onid);
LE16( 0x48e, pmt_pid);
LE16( 0x490, video_pid);
// LE8( 0x498, definition);
LE8( 0x4bc, definition);
LE16( 0x49c, audio_pid);
LE32( 0x4f8, schedstart);
LE32( 0x4fc, scheddur);
LE8( 0x514, genre);
STRING( 0x516, title, 51);
STRING( 0x616, synopsis, 255);
LE16( 0x716, event_id);
LE8( 0x73d, xflags1);
LE8( 0x73e, xflags2);
LE8( 0x73f, xflags3);
LE8( 0x10, series);
LE8( 0x11, episode);
LE8( 0x12, episodetot);
}
int
hmt_is(struct hmt *hmt, enum hmt_attribute attr)
{
switch (attr)
{
case HMTA_ENCRYPTED:
return hmt->flags2 & 0x1;
case HMTA_GHOST:
return hmt->flags2 & 0x8;
case HMTA_LOCKED:
return hmt->flags1 & 0x4;
case HMTA_NEW:
return !(hmt->flags1 & 0x8);
case HMTA_ENCFLAGGED:
return hmt->flags3 != 4;
case HMTA_UNLIMITEDCOPY:
return hmt->flags3 & 0x4;
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 == 0x2;
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_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;
}
}