forked from hummypkg/hmt
prpr
b341756468
Modify iPlate guidance also. Add/correct/use manifest constants. Update filename location to offset 0x180.
424 lines
7.9 KiB
C
424 lines
7.9 KiB
C
#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_GUIDETYPE, HMT_GUIDETYPE_ON);
|
|
patch_byte(hmt, HMT_GUIDEMODE, HMT_GUIDEMODE_ON);
|
|
patch_byte(hmt, HMT_GUIDETYPE2, HMT_GUIDETYPE_ON);
|
|
patch_byte(hmt, HMT_GUIDEMODE2, HMT_GUIDEMODE_ON);
|
|
}
|
|
else
|
|
{
|
|
patch_byte(hmt, HMT_GUIDETYPE, HMT_GUIDETYPE_OFF);
|
|
patch_byte(hmt, HMT_GUIDEMODE, HMT_GUIDEMODE_OFF);
|
|
patch_byte(hmt, HMT_GUIDETYPE2, HMT_GUIDETYPE_OFF);
|
|
patch_byte(hmt, HMT_GUIDEMODE2, HMT_GUIDEMODE_OFF);
|
|
}
|
|
hmt->modified++;
|
|
}
|
|
|
|
void
|
|
cmd_protect(struct hmt *hmt, int flag)
|
|
{
|
|
CHECK_OFFSET(HMT_FLAGS3)
|
|
|
|
if (flag)
|
|
hmt->bin[HMT_FLAGS3] = HMT_FLAGS3_PROTECTED_COPY_UNLIMITED;
|
|
else
|
|
hmt->bin[HMT_FLAGS3] = HMT_FLAGS3_UNPROTECTED;
|
|
hmt->modified++;
|
|
}
|
|
|
|
void
|
|
cmd_encrypted(struct hmt *hmt, int flag)
|
|
{
|
|
CHECK_OFFSET(HMT_FLAGS2);
|
|
|
|
if (flag)
|
|
hmt->bin[HMT_FLAGS2] |= HMT_FLAGS2_ENCRYPTED;
|
|
else
|
|
hmt->bin[HMT_FLAGS2] &= ~HMT_FLAGS2_ENCRYPTED;
|
|
hmt->modified++;
|
|
}
|
|
|
|
void
|
|
cmd_thumbnail(struct hmt *hmt, int flag)
|
|
{
|
|
CHECK_OFFSET(HMT_FLAGS2);
|
|
|
|
if (flag)
|
|
hmt->bin[HMT_FLAGS2] |= HMT_FLAGS2_THUMBNAIL;
|
|
else
|
|
hmt->bin[HMT_FLAGS2] &= ~HMT_FLAGS2_THUMBNAIL;
|
|
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] = (uint8_t)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 = strtol(resume, (char **)NULL, 10);
|
|
|
|
CHECK_OFFSET(HMT_PLAYED_TIME)
|
|
|
|
if (r < 0)
|
|
{
|
|
uint32_t d;
|
|
d = hmt->end - hmt->start;
|
|
printf("Recording Duration:%u\n", d);
|
|
r += d;
|
|
}
|
|
|
|
printf("Setting resume point to: %u 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_utf8(hmt, k + offset, len, str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cmd_settitle(struct hmt *hmt, char *str)
|
|
{
|
|
patch_string(hmt, HMT_TITLE, HMT_TITLE_LEN, str);
|
|
patch_string_utf8(hmt, HMT_ITITLE, HMT_ITITLE_LEN, str);
|
|
patch_epg_offset(hmt, HMT_EPG_TITLE, HMT_TITLE_LEN, str);
|
|
}
|
|
|
|
void
|
|
cmd_setsynopsis(struct hmt *hmt, char *str)
|
|
{
|
|
patch_string_utf8(hmt, HMT_SYNOPSIS, HMT_SYNOPSIS_LEN, str);
|
|
patch_epg_offset(hmt, HMT_EPG_SYNOPSIS, HMT_SYNOPSIS_LEN, str);
|
|
}
|
|
|
|
void
|
|
cmd_setguidance(struct hmt *hmt, char *str)
|
|
{
|
|
cmd_guidance(hmt, !0);
|
|
patch_string_utf8(hmt, HMT_GUIDANCE, HMT_GUIDANCE_LEN, str);
|
|
patch_string_utf8(hmt, HMT_GUIDANCE2, HMT_GUIDANCE_LEN, str);
|
|
patch_epg_offset(hmt, HMT_EPG_GUIDANCE, HMT_GUIDANCE_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] = (uint8_t)series;
|
|
hmt->bin[HMT_EPISODE] = (uint8_t)episode;
|
|
hmt->bin[HMT_EPISODETOT] = (uint8_t)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_string_utf8(struct hmt *hmt, uint32_t offset, uint32_t len, char *str)
|
|
{
|
|
CHECK_OFFSET(offset + strlen(str))
|
|
|
|
if (*str > 0x1F)
|
|
hmt->bin[offset++] = 0x15;
|
|
|
|
patch_string(hmt, offset, len, str);
|
|
}
|
|
|
|
void
|
|
patch_uint16(struct hmt *hmt, uint32_t offset, uint16_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(%u) = %#x(%u)\n", width,
|
|
offset, offset, val, val);
|
|
|
|
switch(width)
|
|
{
|
|
case 8:
|
|
patch_byte(hmt, offset, (uint8_t)val);
|
|
break;
|
|
case 16:
|
|
patch_uint16(hmt, offset, (uint16_t)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(%u)\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("%d %#x\n", val, val);
|
|
break;
|
|
}
|
|
default:
|
|
printf("Unknown patch width.\n");
|
|
break;
|
|
}
|
|
}
|