hmt/file.c

254 lines
6.7 KiB
C
Raw Permalink Normal View History

2011-04-30 00:57:30 +00:00
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <time.h>
#include <strings.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "lint.h"
struct hmt *
open_file(char *filename, int iOpenMode)
{
struct hmt *hmt;
struct stat st;
char *ext;
uint16_t magic;
uint16_t numepgblocks = 0;
uint16_t thisepgblock = 0;
uint8_t numtransportblocks = 0;
uint8_t numguidanceblocks = 0;
int i;
uint16_t thisblocklength;
uint16_t eventid;
int foundit;
if (!(hmt = malloc(sizeof(struct hmt))))
{
perror("malloc");
return NULL;
}
hmt->epgguidance = NULL;
hmt->epgstart = NULL;
if (debug)
printf("Opening file '%s'\n", filename);
strcpy(hmt->fname, filename);
if ((ext = strrchr(hmt->fname, '.')))
{
ext++;
if (debug)
printf(" Extension: '%s'", ext);
if (strcmp(ext, "hmt"))
{
*ext = '\0';
strcat(hmt->fname, "hmt");
}
}
else
strcat(hmt->fname, ".hmt");
if (debug)
printf(" Actual: '%s'\n", hmt->fname);
if (stat(hmt->fname, &st) == -1)
{
perror(hmt->fname);
free(hmt);
return NULL;
}
hmt->binsize = st.st_size;
if (debug)
printf("Opening %s, %lu bytes.\n", hmt->fname,
(unsigned long)hmt->binsize);
if ((hmt->fd = open(hmt->fname, iOpenMode, 0)) == -1)
{
perror(hmt->fname);
free(hmt);
return NULL;
}
if (iOpenMode == O_RDONLY)
{
hmt->bin = (uint8_t *)mmap(NULL, hmt->binsize, PROT_READ,
MAP_SHARED, hmt->fd, 0);
}
else
{
hmt->bin = (uint8_t *)mmap(NULL, hmt->binsize, PROT_READ|PROT_WRITE,
MAP_SHARED, hmt->fd, 0);
}
if (hmt->bin == MAP_FAILED)
{
perror("mmap");
close(hmt->fd);
free(hmt);
return NULL;
}
magic = read_uint16(hmt->bin, 0);
/* if (magic != 0x1701) */
if (magic != 0x0000)
{
printf("Invalid HMT file, %s", hmt->fname);
close_file(hmt);
return NULL;
}
/* Check for non-standard/non-freesat HMTs
Don't try to find the EPG data if this is one of them!
*/
if (hmt->binsize < 0x1004)
{
hmt->epgstart=NULL;
} else {
/*
Need to find the correct EPG entry after the main HMT Block at the start of the file
If the recording spans multiple EPG entries there will be the same number of EPG blocks
each of which may have one or more Guidance Blocks and/or one or more Transport Stream
blocks.
Two possible ways of doing this:
1. If the recording was an EPG based recording then the target event ID will be located in the header block
at offset 0x36b (2 bytes) and also in the EPG block at offset 0x00. This can be used for a definite match.
2. For manual record on demand and manual timed recordings the event ID is not present in the header so have to
find the correct EPG block using a text based comparison of the programme titles.
*/
/* First EPG Block starts at the end of the HMT Block */
hmt->epgstart = (hmt->bin + 0x1004);
numepgblocks = read_uint16(hmt->bin + (HMT_BLOCK_LENGTH - 1), 0);
thisepgblock=1;
foundit = 0;
eventid = read_uint16(hmt->bin + HMT_HEADER_PROG_EV_ID, 0);
if (eventid == 0) {
/* This is a manual recording where the eventid is not present so use string matching to find the EPG block */
while ((strcmp((char *)hmt->epgstart+HMT_EPG_TITLE, (char *)hmt->bin+HMT_TITLE)!=0) && (thisepgblock <= numepgblocks)) {
/* This is not the correct epg entry so skip to next one */
numtransportblocks = hmt->epgstart[(HMT_EPG_BLOCK_LENGTH - 11)];
numguidanceblocks = hmt->epgstart[(HMT_EPG_BLOCK_LENGTH - 10)];
hmt->epgstart = hmt->epgstart + HMT_EPG_BLOCK_LENGTH;
for (i=0; i< (numtransportblocks+numguidanceblocks); i++) {
/* Skip this guidance or transport block as it's not the correct EPG entry */
thisblocklength = read_uint16(hmt->epgstart+2, 0);
hmt->epgstart = hmt->epgstart + thisblocklength + 4;
}
thisepgblock++;
}
if (strcmp((char *)hmt->epgstart+HMT_EPG_TITLE, (char *)hmt->bin+HMT_TITLE) == 0) {
foundit = 1;
}
} else {
/* This is an Event Based (EPG Based) recording so find the EPG Block using the Event ID */
while ((read_uint16(hmt->epgstart, 0) != eventid) && (thisepgblock <= numepgblocks)) {
/* This is not the correct epg entry so skip to next one */
numtransportblocks = hmt->epgstart[(HMT_EPG_BLOCK_LENGTH - 11)];
numguidanceblocks = hmt->epgstart[(HMT_EPG_BLOCK_LENGTH - 10)];
hmt->epgstart = hmt->epgstart + HMT_EPG_BLOCK_LENGTH;
for (i=0; i< (numtransportblocks+numguidanceblocks); i++) {
/* Skip this guidance or transport block as it's not the correct EPG entry */
thisblocklength = read_uint16(hmt->epgstart+2, 0);
hmt->epgstart = hmt->epgstart + thisblocklength + 4;
}
thisepgblock++;
}
if (read_uint16(hmt->epgstart, 0) == eventid) {
foundit = 1;
}
}
/* Check that we've found the EPG block ..... if not, revert to the first EPG block in the file.
This can happen if, for example, the recording was a manual recording which has been renamed so
there's no event ID and the title strings between the header and the EPG block don't match.
*/
if (foundit == 0) {
hmt->epgstart = (hmt->bin + 0x1004);
}
/* So now we have the start of the correct EPG record.
See if there's any guidance blocks and if so, set the relevant pointer
for the start of the Guidance test.
Note - Foxsat HDR HMT files can contain multiple Guidance Blocks - return the first one */
numguidanceblocks = hmt->epgstart[(HMT_EPG_BLOCK_LENGTH - 10)];
if (numguidanceblocks != 0) {
hmt->epgguidance = hmt->epgstart + HMT_EPG_BLOCK_LENGTH;
/* Skip any transport blocks first */
numtransportblocks = hmt->epgstart[(HMT_EPG_BLOCK_LENGTH - 11)];
if (numtransportblocks != 0) {
for(i=0; i<numtransportblocks; i++) {
thisblocklength = read_uint16(hmt->epgguidance+2, 0);
hmt->epgguidance = hmt->epgguidance + thisblocklength + 4;
}
}
/* Pointer now at the start of the guidance block
so now set it to the Guidance Text itself */
hmt->epgguidance = hmt->epgguidance + 21;
}
}
return hmt;
}
void
close_file(struct hmt *hmt)
{
if (debug)
printf("Closing file.\n");
munmap((void *)hmt->bin, hmt->binsize);
if (hmt->fd > 0)
close(hmt->fd);
hmt->fd = -1;
}
struct hmt *
extend_file(struct hmt *hmt, uint32_t extra_size)
{
FILE *file = NULL;
void *nul = NULL;
/*
* No portable way of extending a memory mapped file, just close it, append
* extra bytes and reopen.
*/
close_file(hmt);
if (debug)
printf("Extending file by %d byte(s)\n", extra_size);
if (file = fopen(hmt->fname, "ab")) {
nul = malloc(extra_size);
memset(nul, 0, extra_size);
fwrite(nul, 1, extra_size, file);
fclose(file);
free(nul);
nul = NULL;
}
return open_file(hmt->fname, O_RDWR);
}