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