9 changed files with 1779 additions and 0 deletions
@ -0,0 +1,70 @@
|
||||
|
||||
MAKE=make
|
||||
|
||||
# Setting these makes sure that the subsequent include files know that
|
||||
# we are going to be threaded so they should do whatever they need to
|
||||
# support this. In particular, this makes the global variable 'errno'
|
||||
# become thread safe by replacing it with a call to the internal function
|
||||
# ___errno() on Solaris - and should do something similar on other operating
|
||||
# systems. Solaris also supports _TS_ERRNO to enable thread-safe errno
|
||||
# _REENTRANT is also required for the tempnam() function to be properly
|
||||
# thread-safe.
|
||||
DEFS=-D_REENTRANT -D_TS_ERRNO -DHMT_PROTECT
|
||||
# -DWITH_MPATROL
|
||||
|
||||
SRCS= cmd.c \
|
||||
display.c \
|
||||
file.c \
|
||||
hmt.c \
|
||||
main.c \
|
||||
util.c
|
||||
|
||||
OBJS= $(SRCS:.c=.o)
|
||||
#CC=mipsel-linux-gcc
|
||||
PLATFORM=$(shell uname -s | cut -d- -f1)
|
||||
PROCESSOR=$(shell uname -p)
|
||||
CFLAGS=-g
|
||||
INCS=
|
||||
LIBS=
|
||||
ifeq ($(PLATFORM),CYGWIN_NT) |
||||
CFLAGS=-g -mno-cygwin
|
||||
endif |
||||
#ifeq ($(PLATFORM),Linux)
|
||||
#CFLAGS=-static -g
|
||||
#endif
|
||||
#CFLAGS=-g -O3 -fno-strict-aliasing
|
||||
#WARN=-pedantic -Wall -Wnested-externs -Wpointer-arith -Werror -Wno-unused
|
||||
WARN=-pedantic -Wall -W -Wnested-externs -Wpointer-arith -Wno-long-long
|
||||
|
||||
all: tags hmt |
||||
|
||||
hmt: ${OBJS} |
||||
@echo "Linking..."
|
||||
@-[ -f $@ ] && mv $@ $@~ || exit 0
|
||||
${CC} -static-libgcc \
|
||||
${WARN} \
|
||||
${DEFS} \
|
||||
${CFLAGS} -o $@ \
|
||||
${OBJS} \
|
||||
${LIBS}
|
||||
@echo "Done..."
|
||||
|
||||
clean: |
||||
@-touch core
|
||||
rm -f hmt hmt~ *.exe core tags asm ${OBJS} ${AROBJS}
|
||||
rm -f *.raw *.raw.sum *.lh5
|
||||
rm -rf hmt-*
|
||||
|
||||
tags: |
||||
@-ctags *.[ch] 2>> /dev/null
|
||||
|
||||
.c.o: |
||||
@echo " $<"
|
||||
@$(CC) $(CFLAGS) ${WARN} ${DEFS} ${INCS} -c $< -o $@
|
||||
|
||||
install: hmt |
||||
strip hmt
|
||||
cp hmt /mod/bin/hmt
|
||||
|
||||
${OBJS}: lint.h |
||||
|
@ -0,0 +1,396 @@
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include "lint.h" |
||||
|
||||
#define CHECK_OFFSET(xxx) \ |
||||
if (hmt->binsize < (xxx)) \
|
||||
{ \
|
||||
printf("File too small to patch.\n"); \
|
||||
return; \
|
||||
} |
||||
|
||||
void |
||||
cmd_new(struct hmt *hmt, int flag) |
||||
{ |
||||
CHECK_OFFSET(HMT_FLAGS1) |
||||
|
||||
if (flag) |
||||
hmt->bin[HMT_FLAGS1] &= ~HMT_FLAGS1_NEW; |
||||
else |
||||
hmt->bin[HMT_FLAGS1] |= HMT_FLAGS1_NEW; |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_lock(struct hmt *hmt, int flag) |
||||
{ |
||||
CHECK_OFFSET(HMT_FLAGS1) |
||||
|
||||
if (flag) |
||||
hmt->bin[HMT_FLAGS1] |= HMT_FLAGS1_LOCKED; |
||||
else |
||||
hmt->bin[HMT_FLAGS1] &= ~HMT_FLAGS1_LOCKED; |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_guidance(struct hmt *hmt, int flag) |
||||
{ |
||||
/* 0x03E0 2 byte 'Guide' flag for Media List.
|
||||
0xFF00 = Guide off. 0x0101 = Guide on. */ |
||||
if (flag) |
||||
{ |
||||
patch_byte(hmt, HMT_GUIDEFLAG, 0x01); |
||||
patch_byte(hmt, HMT_GUIDEFLAG + 1, 0x01); |
||||
} |
||||
else |
||||
{ |
||||
patch_byte(hmt, HMT_GUIDEFLAG, 0xff); |
||||
patch_byte(hmt, HMT_GUIDEFLAG + 1, 0x00); |
||||
} |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_protect(struct hmt *hmt, int flag) |
||||
{ |
||||
CHECK_OFFSET(HMT_FLAGS2) |
||||
|
||||
if (flag) |
||||
hmt->bin[HMT_FLAGS2] = 0; |
||||
else |
||||
hmt->bin[HMT_FLAGS2] = 4; |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_encrypted(struct hmt *hmt, int flag) |
||||
{ |
||||
CHECK_OFFSET(HMT_ENCRYPTED); |
||||
|
||||
if (flag) |
||||
hmt->bin[HMT_ENCRYPTED] |= HMT_IS_ENCRYPTED; |
||||
else |
||||
hmt->bin[HMT_ENCRYPTED] &= ~HMT_IS_ENCRYPTED; |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_shrunk(struct hmt *hmt, int flag) |
||||
{ |
||||
CHECK_OFFSET(HMT_SHRUNK); |
||||
|
||||
if (flag) |
||||
hmt->bin[HMT_SHRUNK] = 'E'; |
||||
else |
||||
hmt->bin[HMT_SHRUNK] = 'e'; |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_dedup(struct hmt *hmt, int flag) |
||||
{ |
||||
CHECK_OFFSET(HMT_DEDUPED); |
||||
|
||||
if (flag) |
||||
hmt->bin[HMT_DEDUPED] = 'N'; |
||||
else |
||||
hmt->bin[HMT_DEDUPED] = 'n'; |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_detectads(struct hmt *hmt, int flag) |
||||
{ |
||||
CHECK_OFFSET(HMT_DETECTADS); |
||||
|
||||
if (flag) |
||||
hmt->bin[HMT_DETECTADS] = 'G'; |
||||
else |
||||
hmt->bin[HMT_DETECTADS] = 'g'; |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_setgenre(struct hmt *hmt, char *g) |
||||
{ |
||||
CHECK_OFFSET(HMT_GENRE) |
||||
|
||||
printf("Current genre: %s\n", genredescr(hmt->bin[HMT_GENRE])); |
||||
if (*g == '-') |
||||
hmt->bin[HMT_GENRE] = atoi(g + 1); |
||||
else |
||||
hmt->bin[HMT_GENRE] = genrecode(g); |
||||
printf("Set genre to: %s\n", genredescr(hmt->bin[HMT_GENRE])); |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_setresume(struct hmt *hmt, char *resume) |
||||
{ |
||||
int32_t r = strtoll(resume, (char **)NULL, 10); |
||||
|
||||
CHECK_OFFSET(HMT_PLAYED_TIME) |
||||
|
||||
if (r < 0) |
||||
{ |
||||
uint32_t d; |
||||
d = hmt->end - hmt->start; |
||||
printf("Recording Duration:%lu\n", d); |
||||
r += d; |
||||
} |
||||
|
||||
printf("Setting resume point to: %lu second(s) in.\n", r); |
||||
write_uint32(hmt->bin + HMT_PLAYED_TIME, r); |
||||
hmt->modified++; |
||||
} |
||||
|
||||
static void |
||||
patch_epg_offset(struct hmt *hmt, uint32_t offset, uint32_t len, char *str) |
||||
{ |
||||
if (hmt->binsize > 0x1001) |
||||
{ |
||||
uint32_t j, k; |
||||
uint32_t n; |
||||
|
||||
/* Read the number of EPG blocks. */ |
||||
j = read_uint16(hmt->bin + 0x1000, 1); |
||||
|
||||
/* Loop through them. */ |
||||
for (n = 1; n <= j; n++) |
||||
{ |
||||
/* Offset of block header. */ |
||||
uint32_t off = 0x1004 + n * 32; |
||||
|
||||
if (hmt->binsize < off) |
||||
break; |
||||
|
||||
/* Read offset of EPG data. */ |
||||
k = read_uint32(hmt->bin + off + 8, 1); |
||||
|
||||
if (k < off) |
||||
continue; |
||||
|
||||
if (hmt->binsize >= k + 704) |
||||
{ |
||||
if (debug) |
||||
printf("Patching EPG block %d.\n", n); |
||||
patch_string(hmt, k + offset, len, str); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void |
||||
cmd_settitle(struct hmt *hmt, char *str) |
||||
{ |
||||
patch_string(hmt, HMT_TITLE, HMT_TITLE_LEN, str); |
||||
patch_string(hmt, HMT_ITITLE, HMT_ITITLE_LEN, str); |
||||
patch_epg_offset(hmt, 0x3e, HMT_TITLE_LEN, str); |
||||
} |
||||
|
||||
void |
||||
cmd_setsynopsis(struct hmt *hmt, char *str) |
||||
{ |
||||
CHECK_OFFSET(HMT_EPG) |
||||
|
||||
if (strlen(str) >= HMT_EPG_LEN) |
||||
{ |
||||
fprintf(stderr, "New synopsis too long.\n"); |
||||
return; |
||||
} |
||||
|
||||
patch_string(hmt, HMT_EPG, HMT_EPG_LEN, str); |
||||
patch_epg_offset(hmt, 0x141, HMT_EPG_LEN, str); |
||||
} |
||||
|
||||
void |
||||
cmd_setseries(struct hmt *hmt, char *g) |
||||
{ |
||||
unsigned int series, episode, episodes; |
||||
|
||||
if (sscanf(g, "%u,%u,%u", &series, &episode, &episodes) >= 2) |
||||
{ |
||||
hmt->bin[HMT_SERIES] = series; |
||||
hmt->bin[HMT_EPISODE] = episode; |
||||
hmt->bin[HMT_EPISODETOT] = episodes; |
||||
hmt->modified++; |
||||
} |
||||
else |
||||
printf("Invalid episode '%s'\n", g); |
||||
} |
||||
|
||||
static int |
||||
intcomp(const void *a, const void *b) |
||||
{ |
||||
return (*(uint32_t *)a - *(uint32_t *)b); |
||||
} |
||||
|
||||
void |
||||
cmd_bookmarks(struct hmt *hmt, char *str, int add) |
||||
{ |
||||
uint32_t *b = (uint32_t *)(hmt->bin + HMT_BOOKMARKS); |
||||
uint16_t n = read_uint16(hmt->bin + HMT_BOOKMARKS_CNT, 1); |
||||
char *p; |
||||
|
||||
if (!add) |
||||
n = 0; |
||||
if (!str || !(p = strtok(str, ":"))) |
||||
{ |
||||
/* No bookmarks provided. */ |
||||
if (add) |
||||
return; |
||||
*(uint16_t *)(hmt->bin + HMT_BOOKMARKS_CNT) = 0; |
||||
hmt->modified++; |
||||
return; |
||||
} |
||||
|
||||
do |
||||
{ |
||||
if (n >= 32) |
||||
{ |
||||
fprintf(stderr, "Too many bookmarks, maximum 32.\n"); |
||||
return; |
||||
} |
||||
b[n++] = (uint32_t)strtoul(p, (char **)NULL, 10); |
||||
hmt->modified++; |
||||
} while ((p = strtok((char *)NULL, ":"))); |
||||
*(uint16_t *)(hmt->bin + HMT_BOOKMARKS_CNT) = n; |
||||
|
||||
qsort(b, n, sizeof(uint32_t), intcomp); |
||||
} |
||||
|
||||
void |
||||
patch_byte(struct hmt *hmt, uint32_t offset, uint8_t val) |
||||
{ |
||||
CHECK_OFFSET(offset) |
||||
|
||||
if (hmt->bin[offset] != val) |
||||
{ |
||||
hmt->bin[offset] = val; |
||||
hmt->modified++; |
||||
} |
||||
} |
||||
|
||||
void |
||||
patch_string(struct hmt *hmt, uint32_t offset, uint32_t len, char *str) |
||||
{ |
||||
CHECK_OFFSET(offset + strlen(str)) |
||||
|
||||
if (debug > 3) |
||||
fprintf(stderr, "patch_string(%#x, %d, %s)\n", |
||||
offset, len, str); |
||||
|
||||
memset(hmt->bin + offset, '\0', len - 1); |
||||
strcpy((char *)(hmt->bin + offset), (const char *)str); |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
patch_uint16(struct hmt *hmt, uint32_t offset, uint32_t val) |
||||
{ |
||||
CHECK_OFFSET(offset) |
||||
|
||||
write_uint16(hmt->bin + offset, val); |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
patch_uint32(struct hmt *hmt, uint32_t offset, uint32_t val) |
||||
{ |
||||
CHECK_OFFSET(offset) |
||||
|
||||
write_uint32(hmt->bin + offset, val); |
||||
hmt->modified++; |
||||
} |
||||
|
||||
void |
||||
cmd_patch(struct hmt *hmt, char *str) |
||||
{ |
||||
int width; |
||||
uint32_t offset; |
||||
uint32_t val; |
||||
char offsets[0x20], vals[0x20]; |
||||
|
||||
if (sscanf(str, "%d=%[^:]:%s", &width, offsets, vals) != 3) |
||||
{ |
||||
printf("Syntax error.\n"); |
||||
return; |
||||
} |
||||
|
||||
offset = strtoul(offsets, (char **)NULL, 0); |
||||
val = strtoul(vals, (char **)NULL, 0); |
||||
|
||||
printf("Patching width %d - %#x(%lu) = %#x(%lu)\n", width, |
||||
offset, offset, val, val); |
||||
|
||||
switch(width) |
||||
{ |
||||
case 8: |
||||
patch_byte(hmt, offset, val); |
||||
break; |
||||
case 16: |
||||
patch_uint16(hmt, offset, val); |
||||
break; |
||||
case 32: |
||||
patch_uint32(hmt, offset, val); |
||||
break; |
||||
default: |
||||
printf("Unknown patch width.\n"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void |
||||
cmd_unpatch(struct hmt *hmt, char *str) |
||||
{ |
||||
int width; |
||||
uint32_t offset; |
||||
char offsets[0x20]; |
||||
|
||||
if (sscanf(str, "%d=%[^:]", &width, offsets) != 2) |
||||
{ |
||||
printf("Syntax error.\n"); |
||||
return; |
||||
} |
||||
|
||||
offset = strtoul(offsets, (char **)NULL, 0); |
||||
|
||||
if (hmt->binsize < offset) |
||||
{ |
||||
printf("Offset too large for file.\n"); |
||||
return; |
||||
} |
||||
|
||||
if (debug) |
||||
printf("Reading width %d - %#x(%lu)\n", width, |
||||
offset, offset); |
||||
|
||||
switch(width) |
||||
{ |
||||
case 8: |
||||
{ |
||||
uint8_t val = hmt->bin[offset] & 0xff; |
||||
printf("%d %#x\n", val, val); |
||||
break; |
||||
} |
||||
case 16: |
||||
{ |
||||
uint16_t val = read_uint16(hmt->bin + offset, 1); |
||||
printf("%d %#x\n", val, val); |
||||
break; |
||||
} |
||||
case 32: |
||||
{ |
||||
uint32_t val = read_uint32(hmt->bin + offset, 1); |
||||
printf("%ld %#x\n", val, val); |
||||
break; |
||||
} |
||||
default: |
||||
printf("Unknown patch width.\n"); |
||||
break; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,155 @@
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
#include "lint.h" |
||||
|
||||
char * |
||||
ctimenl(uint32_t *tm) |
||||
{ |
||||
static char buf[25]; |
||||
char *p; |
||||
|
||||
strcpy(buf, ctime((time_t *)tm)); |
||||
|
||||
if ((p = strpbrk(buf, "\r\n"))) |
||||
*p = '\0'; |
||||
|
||||
return buf; |
||||
} |
||||
|
||||
void |
||||
display_bookmarks(struct hmt *hmt) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < hmt->num_bookmarks && i < 32; i++) |
||||
printf("%d ", hmt->bookmarks[i]); |
||||
printf("\n"); |
||||
} |
||||
|
||||
void |
||||
display_hmt(struct hmt *hmt) |
||||
{ |
||||
int g; |
||||
|
||||
g = guidance(hmt); |
||||
|
||||
if (sysopts & SYSOPT_PARSABLE) |
||||
{ |
||||
printf("%s\t", hmt->mediatitle); |
||||
printf("%s\t", hmt->synopsis); |
||||
printf("%s\t", hmt->definition == DEF_HD ? "HD" : "SD"); |
||||
printf("%lu\t%s\t", hmt->lcn, hmt->channel); |
||||
printf("%lu\t", hmt->start); |
||||
printf("%lu\t", hmt->end); |
||||
printf("%s\t", hmt_flags(hmt)); |
||||
if (g) |
||||
printf("%s\t", hmt->guidance); |
||||
else |
||||
printf("\t"); |
||||
|
||||
printf("%d\t", hmt->num_bookmarks); |
||||
printf("%lu\t", hmt->schedstart); |
||||
printf("%lu\t", hmt->scheddur); |
||||
printf("%d\t", hmt->genre); |
||||
printf("%lu\t", hmt->resume); |
||||
printf("%s/%s\t", recordingstatus(hmt), failurereason(hmt)); |
||||
printf("%u\t%u\t%u\t", hmt->series, hmt->episode, |
||||
hmt->episodetot); |
||||
|
||||
printf("\n"); |
||||
|
||||
return; |
||||
} |
||||
|
||||
printf("Format:%s\n", hmt->definition == DEF_HD ? "HD" : "SD"); |
||||
printf("Title:%s\n", hmt->mediatitle); |
||||
printf("ITitle:%s\n", hmt->title); |
||||
printf("Channel:%lu (%s)\n", hmt->lcn, hmt->channel); |
||||
printf("Episode:%u,%u/%u\n", |
||||
hmt->series, hmt->episode, hmt->episodetot); |
||||
|
||||
printf("Folder:%s\n", hmt->directory); |
||||
if (*hmt->filename == '\0' && hmt->filename[1] != '\0') |
||||
printf("Filename:%s\n", hmt->filename + 1); |
||||
else |
||||
printf("Filename:%s\n", hmt->filename); |
||||
|
||||
printf("Genre:%s (%d)\n", genredescr(hmt->genre), hmt->genre); |
||||
printf("EPG:%s\n", hmt->synopsis); |
||||
if (g) |
||||
printf("Guidance:%s\n", hmt->guidance); |
||||
|
||||
if (hmt_is(hmt, HMTA_ENCRYPTED)) |
||||
printf("Raw file is encrypted on disk.\n"); |
||||
|
||||
printf("\n"); |
||||
|
||||
printf("Recording Status: %s (%s)\n", |
||||
recordingstatus(hmt), failurereason(hmt)); |
||||
printf("Flags: %s\n", hmt_flags(hmt)); |
||||
printf("Copy count:%d\n", hmt->copycount); |
||||
|
||||
printf("\n"); |
||||
|
||||
printf("Scheduled start:%lu (%s)\n", hmt->schedstart, |
||||
ctimenl(&hmt->schedstart)); |
||||
printf("Scheduled duration:%lu\n", hmt->scheddur); |
||||
printf("Recording start:%lu (%s)\n", hmt->start, |
||||
ctimenl(&hmt->start)); |
||||
printf("Recording end:%lu (%s)\n", hmt->end, ctimenl(&hmt->end)); |
||||
printf("Duration:%lu\n", hmt->end - hmt->start); |
||||
printf("Stored duration:%lu\n", hmt->duration); |
||||
|
||||
printf("Play resumes at:%lu second%s in.\n", hmt->resume, |
||||
hmt->resume == 1 ? "" : "s"); |
||||
printf("Timezone offset:%d\n", hmt->tzoffset); |
||||
|
||||
printf("\n"); |
||||
|
||||
printf("Service ID (SID):%u\n", hmt->service_id); |
||||
printf("Event ID:%u\n", hmt->event_id); |
||||
printf("Transport Stream ID (TSID):%u\n", hmt->tsid); |
||||
printf("Originating Network ID (ONID):%u\n", hmt->onid); |
||||
printf("Programme Map Table PID (PMTPID):%u\n", hmt->pmt_pid); |
||||
printf("Video PID:%u\n", hmt->video_pid); |
||||
printf("Audio PID:%u\n", hmt->audio_pid); |
||||
printf("Bookmarks:%d = ", hmt->num_bookmarks); |
||||
display_bookmarks(hmt); |
||||
|
||||
/* Display basic information EPG blocks... TBC */ |
||||
if (hmt->binsize > 0x1001) |
||||
{ |
||||
uint16_t j, k; |
||||
int n; |
||||
|
||||
printf("\n"); |
||||
j = read_uint16(hmt->bin + 0x1000, 1); |
||||
printf("EPG Blocks:%u\n", j); |
||||
for (n = 1; n <= j; n++) |
||||
{ |
||||
uint32_t off = 0x1004 + n * 32; |
||||
if (hmt->binsize < off) |
||||
break; |
||||
printf(" Block:%d", n); |
||||
k = read_uint32(hmt->bin + off + 4, 1); |
||||
printf(" Time:%lu", k); |
||||
k = read_uint32(hmt->bin + off + 8, 1); |
||||
printf(" Offset:%#x\n", k); |
||||
|
||||
if (k < off) |
||||
continue; |
||||
|
||||
if (hmt->binsize >= k + 704) |
||||
{ |
||||
/* Offset to EPG block. */ |
||||
off = k; |
||||
printf(" Block%d_Title:%s\n", n, |
||||
strip_string(hmt->bin + off + 0x3e)); |
||||
} |
||||
|
||||
/* Synopsis is off + 0x141 */ |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,139 @@
|
||||
#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 readonly) |
||||
{ |
||||
struct hmt *hmt; |
||||
struct stat st; |
||||
char *ext; |
||||
uint16_t magic; |
||||
|
||||
if (!(hmt = malloc(sizeof(struct hmt)))) |
||||
{ |
||||
perror("malloc"); |
||||
return NULL; |
||||
} |
||||
|
||||
if (debug) |
||||
printf("Opening file '%s' (readonly=%d)\n", filename, readonly); |
||||
|
||||
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); |
||||
|
||||
hmt->readonly = readonly; |
||||
|
||||
if ((hmt->fd = open(hmt->fname, readonly ? O_RDONLY : O_RDWR, 0)) == -1) |
||||
{ |
||||
perror(hmt->fname); |
||||
free(hmt); |
||||
return NULL; |
||||
} |
||||
|
||||
hmt->bin = (uint8_t *)mmap(NULL, hmt->binsize, |
||||
readonly ? PROT_READ : PROT_READ|PROT_WRITE, |
||||
MAP_SHARED, hmt->fd, 0); |
||||
if (hmt->bin == MAP_FAILED) |
||||
{ |
||||
if (debug) |
||||
printf("mmap() failed, falling back to read.\n"); |
||||
/* This occurs if the underlying filesystem does not support
|
||||
* mmap, e.g. NTFS. Fallback to holding the file in memory. |
||||
*/ |
||||
if (!(hmt->bin = (uint8_t *)malloc(hmt->binsize))) |
||||
{ |
||||
perror("malloc"); |
||||
free(hmt); |
||||
close(hmt->fd); |
||||
return NULL; |
||||
} |
||||
read(hmt->fd, hmt->bin, hmt->binsize); |
||||
hmt->mmapped = 0; |
||||
} |
||||
else |
||||
{ |
||||
if (debug) |
||||
printf("File mapped into memory.\n"); |
||||
hmt->mmapped = 1; |
||||
} |
||||
|
||||
magic = read_uint16(hmt->bin, 0); |
||||
|
||||
if (magic != 0x1701) |
||||
{ |
||||
printf("Invalid HMT file, %s\n", hmt->fname); |
||||
close_file(hmt); |
||||
return NULL; |
||||
} |
||||
|
||||
hmt->modified = 0; |
||||
parse_hmt(hmt); |
||||
|
||||
return hmt; |
||||
} |
||||
|
||||
void |
||||
close_file(struct hmt *hmt) |
||||
{ |
||||
if (debug) |
||||
printf("Closing file.\n"); |
||||
|
||||
if (hmt->mmapped) |
||||
munmap((void *)hmt->bin, hmt->binsize); |
||||
else |
||||
{ |
||||
if (hmt->modified && !hmt->readonly) |
||||
{ |
||||
lseek(hmt->fd, SEEK_SET, 0); |
||||
write(hmt->fd, hmt->bin, hmt->binsize); |
||||
} |
||||
free(hmt->bin); |
||||
} |
||||
if (hmt->fd > 0) |
||||
close(hmt->fd); |
||||
hmt->fd = -1; |
||||
} |
||||
|
@ -0,0 +1,263 @@
|
||||
#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 "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 */ |
||||
inline 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"; |
||||
} |
||||
|
||||
int |
||||
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; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,151 @@
|
||||
|
||||
#include <sys/param.h> |
||||
|
||||
enum hmt_attribute { |
||||
HMTA_ENCRYPTED = 0, |
||||
HMTA_LOCKED, |
||||
HMTA_NEW, |
||||
HMTA_ENCFLAGGED, |
||||
HMTA_SHRUNK, |
||||
HMTA_DEDUPED, |
||||
HMTA_DETECTADS, |
||||
HMTA_UNLIMITEDCOPY, |
||||
HMTA_RADIO, |
||||
HMTA_GHOST, |
||||
}; |
||||
|
||||
struct hmt { |
||||
char fname[MAXPATHLEN + 1]; |
||||
int fd; |
||||
uint8_t *bin; |
||||
uint32_t binsize; |
||||
int mmapped; |
||||
int modified; |
||||
int readonly; |
||||
|
||||
/* Recording information */ |
||||
char *directory; |
||||
char *filename; |
||||
uint8_t type; |
||||
uint32_t start; |
||||
uint32_t end; |
||||
uint16_t duration; |
||||
uint8_t recstatus; |
||||
uint8_t flags1; |
||||
uint8_t flags2; |
||||
uint8_t failreason; |
||||
uint32_t resume; |
||||
uint16_t num_bookmarks; |
||||
char *mediatitle; |
||||
uint32_t *bookmarks; |
||||
uint8_t flags3; |
||||
uint8_t guidance_type; |
||||
uint8_t guidance_mode; |
||||
char *guidance; |
||||
uint8_t copycount; |
||||
uint16_t tzoffset; |
||||
uint32_t lcn; |
||||
char *channel; |
||||
uint16_t service_id; |
||||
uint16_t tsid; |
||||
uint16_t onid; |
||||
uint16_t pmt_pid; |
||||
uint16_t video_pid; |
||||
enum { DEF_SD = 1, DEF_HD } definition; |
||||
uint16_t audio_pid; |
||||
uint32_t schedstart; |
||||
uint32_t scheddur; |
||||
uint8_t genre; |
||||
char *title; |
||||
char *synopsis; |
||||
uint16_t event_id; |
||||
uint8_t xflags1; |
||||
uint8_t xflags2; |
||||
uint8_t xflags3; |
||||
|
||||
int series; |
||||
int episode; |
||||
int episodetot; |
||||
}; |
||||
|
||||
void parse_hmt(struct hmt *); |
||||
uint8_t *strip_string(uint8_t *); |
||||
int guidance(struct hmt *); |
||||
const char *genredescr(unsigned char b); |
||||
int genrecode(char *); |
||||
const char *recordingstatus(struct hmt *); |
||||
const char *failurereason(struct hmt *); |
||||
char *hmt_flags(struct hmt *); |
||||
int hmt_is(struct hmt *, enum hmt_attribute); |
||||
|
||||
#define HMT_FOLDER 0x80 |
||||
#define HMT_FOLDER_LEN 254 |
||||
|
||||
#define HMT_FILENAME 0x17f |
||||
#define HMT_FILENAME_LEN 256 |
||||
|
||||
#define HMT_TITLE 0x29a |
||||
#define HMT_TITLE_LEN 48 |
||||
#define HMT_ITITLE 0x516 |
||||
#define HMT_ITITLE_LEN 48 |
||||
|
||||
#define HMT_CHANNEL_NUM 0x458 /* 4 bytes */ |
||||
#define HMT_CHANNEL_NAME 0x45c |
||||
#define HMT_EPG 0x616 |
||||
#define HMT_EPG_LEN 252 |
||||
|
||||
#define HMT_RECSTATUS 0x28c |
||||
#define HMT_FAILREASON 0x290 |
||||
|
||||
#define HMT_RECTYPE 0x4b8 |
||||
|
||||
#define HMT_FLAGS1 0x28d |
||||
#define HMT_FLAGS1_LOCKED 0x4 |
||||
#define HMT_FLAGS1_NEW 0x8 |
||||
|
||||
#define HMT_ENCRYPTED 0x28e |
||||
#define HMT_IS_ENCRYPTED 0x1 |
||||
|
||||
#define HMT_BOOKMARKS_CNT 0x298 |
||||
#define HMT_BOOKMARKS 0x31c |
||||
|
||||
#define HMT_FLAGS2 0x3dc |
||||
#define HMT_FLAGS2_ENCRYPTED 0x2 /* As in "keep encrypted" */ |
||||
#define HMT_FLAGS2_UNLIMITCOPY 0x4 |
||||
|
||||
#define HMT_RECORDING_START 0x280 /* 4 bytes */ |
||||
#define HMT_RECORDING_END 0x284 /* 4 bytes */ |
||||
#define HMT_STORED_DURATION 0x288 /* 2 bytes */ |
||||
#define HMT_SCHEDULED_START 0x4f8 /* 4 bytes */ |
||||
#define HMT_SCHEDULED_DURATION 0x4fc /* 4 bytes */ |
||||
#define HMT_PLAYED_TIME 0x294 /* 4 bytes */ |
||||
#define HMT_GENRE 0x514 |
||||
|
||||
#define HMT_EVENTID 0x716 |
||||
|
||||
#define HMT_GUIDEFLAG 0x3e0 |
||||
#define HMT_GUIDEFLAG_ON 0x01 |
||||
#define HMT_GUIDANCE 0x3e2 |
||||
#define HMT_GUIDANCE_LEN 74 |
||||
|
||||
#define HMT_SID 0x488 /* 2 bytes */ |
||||
#define HMT_TSID 0x48a /* 2 bytes */ |
||||
#define HMT_ONID 0x48c /* 2 bytes */ |
||||
#define HMT_PMTPID 0x48e /* 2 bytes */ |
||||
#define HMT_VIDEOPID 0x490 /* 2 bytes */ |
||||
#define HMT_AUDIOPID 0x49c /* 2 bytes */ |
||||
|
||||
#define HMT_HDFLAG 0x498 /* 1 == SD, 2 == HD */ |
||||
#define HMT_HDFLAG2 0x4bc /* 1 == SD, 0 == HD */ |
||||
|
||||
#define HMT_COPYCOUNT 0x431 |
||||
|
||||
/* Section of HMT used for 'eng' string from guidance text. */ |
||||
#define HMT_SHRUNK 0x73d /* Set to E for shrunk.. */ |
||||
#define HMT_DEDUPED 0x73e /* Set to N for deduped.. */ |
||||
#define HMT_DETECTADS 0x73f /* Set to G for detectads.. */ |
||||
|
||||
#define HMT_SERIES 0x10 |
||||
#define HMT_EPISODE 0x11 |
||||
#define HMT_EPISODETOT 0x12 |
||||
|
@ -0,0 +1,44 @@
|
||||
|
||||
#define SYSOPT_PARSABLE 0x1 |
||||
|
||||
#include "hmt.h" |
||||
|
||||
extern int debug; |
||||
extern const char *version; |
||||
extern unsigned long sysopts; |
||||
|
||||
inline uint16_t read_uint16(uint8_t *, int); |
||||
inline uint32_t read_uint32(uint8_t *, int); |
||||
inline void write_uint32(uint8_t *, uint32_t); |
||||
inline void write_uint16(uint8_t *, uint16_t); |
||||
|
||||
void hexdump(uint8_t *, uint32_t, uint32_t); |
||||
|
||||
struct hmt *open_file(char *, int); |
||||
void close_file(struct hmt *); |
||||
|
||||
void display_bookmarks(struct hmt *hmt); |
||||
void display_hmt(struct hmt *hmt); |
||||
|
||||
void cmd_protect(struct hmt *, int); |
||||
void cmd_encrypted(struct hmt *, int); |
||||
void cmd_shrunk(struct hmt *, int); |
||||
void cmd_dedup(struct hmt *, int); |
||||
void cmd_detectads(struct hmt *, int); |
||||
void cmd_new(struct hmt *, int); |
||||
void cmd_lock(struct hmt *, int); |
||||
void cmd_guidance(struct hmt *, int); |
||||
void cmd_setresume(struct hmt *, char *); |
||||
void cmd_setsynopsis(struct hmt *, char *); |
||||
void cmd_settitle(struct hmt *, char *); |
||||
void cmd_setgenre(struct hmt *, char *); |
||||
void cmd_bookmarks(struct hmt *, char *, int); |
||||
void patch_byte(struct hmt *, uint32_t, uint8_t); |
||||
void patch_string(struct hmt *, uint32_t, uint32_t, char *); |
||||
void cmd_patch(struct hmt *, char *); |
||||
void cmd_unpatch(struct hmt *, char *); |
||||
void cmd_setseries(struct hmt *, char *); |
||||
|
||||
const char *genre(unsigned char); |
||||
int genrecode(char *); |
||||
|
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Humax HMT Tool |
||||
* (c) af123, 2011-2016 |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <ctype.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <sys/time.h> |
||||
#include <sys/stat.h> |
||||
#include <time.h> |
||||
#include "lint.h" |
||||
|
||||
int debug = 0; |
||||
const char *version = "2.0.10"; |
||||
unsigned long sysopts = 0; |
||||
|
||||
int |
||||
syntax() |
||||
{ |
||||
fprintf(stderr, "Humax HMT Tool v%s, by af123, 2011-2016.\n\n", |
||||
version); |
||||
fprintf(stderr, |
||||
"Syntax: hmt [command] <filename> [filename] ...\n"); |
||||
fprintf(stderr, |
||||
" Commands:\n" |
||||
" +/-new Mark/unmark recording as new.\n" |
||||
" +/-lock Mark/unmark recording as locked.\n" |
||||
" +/-guidance Mark/unmark recording as having guidance.\n" |
||||
); |
||||
fprintf(stderr, |
||||
" +/-protect Enable/disable protection" |
||||
" (prevents decryption on copy).\n" |
||||
" +/-encrypted Mark/unmark recording as encrypted.\n" |
||||
" +/-shrunk Mark/unmark recording as shrunk.\n" |
||||
" +/-dedup Mark/unmark recording as deduped.\n" |
||||
" +/-detectads Mark/unmark recording as ad-detection-done.\n" |
||||
); |
||||
fprintf(stderr, |
||||
" -p Display parseable file information (see *).\n" |
||||
" -list Display file information (default).\n" |
||||
" -bookmarks Display bookmarks.\n" |
||||
" +addbookmark=<seconds>[:<seconds>]...\n" |
||||
" +setbookmarks=<seconds>[:<seconds>]...\n" |
||||
" +clearbookmarks\n" |
||||
" +settitle=<new title>\n" |
||||
" +setsynopsis=<new synopsis>\n" |
||||
" +setguidance=<new guidance>\n" |
||||
); |
||||
fprintf(stderr, |
||||
" +setseries=<series,episode,episodes>\n" |
||||
" +setfolder=<new folder> (patch hmt only)\n" |
||||
" +setfilename=<new filename> (patch hmt only)\n" |
||||
" +setgenre=<genre> (can just specifiy initial part)\n" |
||||
" +setresume=<resume point (seconds)> " |
||||
"(-seconds to set from end)\n" |
||||
); |
||||
|
||||
fprintf(stderr, |
||||
"\n" |
||||
"Generic patch commands:\n" |
||||
" +patch8=offset:value patch 8-bit value\n" |
||||
" +patch16=offset:value patch 16-bit value\n" |
||||
" +patch32=offset:value patch 32-bit value\n" |
||||
" Offset and value can be preceeded with 0x to indicate hex.\n" |
||||
); |
||||
|
||||
fprintf(stderr, |
||||
"\n" |
||||
"Generic read commands:\n" |
||||
" +read8=offset read 8-bit value\n" |
||||
" +read16=offset read 16-bit value\n" |
||||
" +read32=offset read 32-bit value\n" |
||||
" Offset can be preceeded with 0x to indicate hex.\n" |
||||
); |
||||
|
||||
fprintf(stderr, |
||||
"\n" |
||||
"* Parseable output is tab delimited and contains the following" |
||||
" fields:\n" |
||||
" Title, Synopsis, HD/SD, LCN, Channel Name,\n" |
||||
" Start time, End time, Flags, Guidance, Bookmark count,\n" |
||||
" Scheduled start, Scheduled duration, Genre code,\n" |
||||
" Resume point, Status/Reason.\n" |
||||
); |
||||
fprintf(stderr, "\n"); |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
main(int argc, char **argv) |
||||
{ |
||||
enum { |
||||
CMD_LIST = 0, |
||||
CMD_NEW, |
||||
CMD_LOCK, |
||||
CMD_PROTECT, |
||||
CMD_GUIDANCE, |
||||
CMD_ENCRYPTED, |
||||
CMD_SHRUNK, |
||||
CMD_DEDUP, |
||||
CMD_DETECTADS, |
||||
CMD_SETTITLE, |
||||
CMD_SETSYNOPSIS, |
||||
CMD_SETGUIDANCE, |
||||
CMD_SETFOLDER, |
||||
CMD_SETSERIES, |
||||
CMD_SETFILENAME, |
||||
CMD_SETGENRE, |
||||
CMD_SETRESUME, |
||||
CMD_BOOKMARKS, |
||||
CMD_ADDBOOKMARK, |
||||
CMD_SETBOOKMARKS, |
||||
CMD_CLEARBOOKMARKS, |
||||
CMD_PATCH, |
||||
CMD_UNPATCH |
||||
} cmd = CMD_LIST; |
||||
char *newstr; |
||||
int i, toggle; |
||||
|
||||
if (argc > 1 && !strncmp(argv[1], "-d", 2)) |
||||
{ |
||||
if (argv[1][2] == '\0') |
||||
debug = 1; |
||||
else |
||||
debug = atoi(argv[1] + 2); |
||||
if (debug > 0) |
||||
{ |
||||
printf("Set debug level to %d\n", debug); |
||||
argc--, argv++; |
||||
} |
||||
} |
||||
|
||||
if (argc > 1 && !strcmp(argv[1], "-p")) |
||||
{ |
||||
sysopts |= SYSOPT_PARSABLE; |
||||
argc--, argv++; |
||||
} |
||||
|
||||
if (argc < 2) |
||||
return syntax(); |
||||
|
||||
toggle = 0; |
||||
switch (*argv[1]) |
||||
{ |
||||
case '+': |
||||
toggle = 1; |
||||
/* Fall-through */ |
||||
case '-': |
||||
if (!strcmp(argv[1] + 1, "list")) |
||||
cmd = CMD_LIST; |
||||
else if (!strcmp(argv[1] + 1, "new")) |
||||
cmd = CMD_NEW; |
||||
else if (!strcmp(argv[1] + 1, "lock")) |
||||
cmd = CMD_LOCK; |
||||
else if (!strcmp(argv[1] + 1, "protect")) |
||||
cmd = CMD_PROTECT; |
||||
else if (!strcmp(argv[1] + 1, "guidance")) |
||||
cmd = CMD_GUIDANCE; |
||||
else if (!strcmp(argv[1] + 1, "encrypted")) |
||||
cmd = CMD_ENCRYPTED; |
||||
else if (!strcmp(argv[1] + 1, "shrunk")) |
||||
cmd = CMD_SHRUNK; |
||||
else if (!strcmp(argv[1] + 1, "dedup")) |
||||
cmd = CMD_DEDUP; |
||||
else if (!strcmp(argv[1] + 1, "detectads")) |
||||
cmd = CMD_DETECTADS; |
||||
else if (!strcmp(argv[1] + 1, "bookmarks")) |
||||
cmd = CMD_BOOKMARKS; |
||||
else if (!strncmp(argv[1], "+patch", 6)) |
||||
{ |
||||
newstr = argv[1] + 6; |
||||
cmd = CMD_PATCH; |
||||
} |
||||
else if (!strncmp(argv[1], "+read", 5)) |
||||
{ |
||||
newstr = argv[1] + 5; |
||||
cmd = CMD_UNPATCH; |
||||
} |
||||
else if (!strncmp(argv[1], "+settitle=", 10)) |
||||
{ |
||||
newstr = argv[1] + 10; |
||||
if (strlen(newstr) >= HMT_TITLE_LEN) |
||||
{ |
||||
fprintf(stderr, "New title too long.\n"); |
||||
return 0; |
||||
} |
||||
cmd = CMD_SETTITLE; |
||||
} |
||||
else if (!strncmp(argv[1], "+setsynopsis=", 13)) |
||||
{ |
||||
newstr = argv[1] + 13; |
||||
cmd = CMD_SETSYNOPSIS; |
||||
} |
||||
else if (!strncmp(argv[1], "+setguidance=", 13)) |
||||
{ |
||||
newstr = argv[1] + 13; |
||||
if (strlen(newstr) >= HMT_GUIDANCE_LEN) |
||||
{ |
||||
fprintf(stderr, "New guidance too long.\n"); |
||||
return 0; |
||||
} |
||||
cmd = CMD_SETGUIDANCE; |
||||
} |
||||
else if (!strncmp(argv[1], "+setseries=", 11)) |
||||
{ |
||||
newstr = argv[1] + 11; |
||||
cmd = CMD_SETSERIES; |
||||
} |
||||
else if (!strncmp(argv[1], "+setfolder=", 11)) |
||||
{ |
||||
newstr = argv[1] + 11; |
||||