hmt/cmd.c
prpr b341756468 Tag string fields to allow UTF-8 or ISO-6937.
Modify iPlate guidance also.
Add/correct/use manifest constants.
Update filename location to offset 0x180.
2022-04-07 02:54:35 +01:00

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;
}
}