/* * Humax EPG Tool * by af123, 2011 */ #include #include #include #include #include #include #include #include #include "lint.h" struct descriptor * read_descriptor_header(struct epg *epg) { struct descriptor *d; d = (struct descriptor *)malloc(sizeof(struct descriptor)); d->loaded = 0; if (epg->binsize - epg->offset < 2) return NULL; memcpy(d, epg->bin + epg->offset, 2); epg->offset += 2; return d; } static char * string_to_end(struct epg *epg, struct descriptor *d, int sofar, unsigned int *len) { int rest = d->len - sofar; char *str; *len = rest; if (rest <= 0) return NULL;; str = (char *)malloc(rest + 1); memcpy(str, epg->bin + epg->offset, rest); str[rest] = '\0'; epg->offset += rest; return str; } static char * read_lstring(struct epg *epg, unsigned int *len) { int l = epg->bin[epg->offset++]; char *c; c = malloc(l + 1); memcpy(c, epg->bin + epg->offset, l); c[l] = '\0'; epg->offset += l; if (len) *len = l; return c; } void read_descriptor(struct epg *epg, struct descriptor *d) { d->loaded = 1; switch (d->tag) { case DS_SHORT_EVENT: memcpy(d->content.d77.lang, epg->bin + epg->offset, 3); epg->offset += 3; d->content.d77.name = read_lstring(epg, &d->content.d77.namelen); d->content.d77.text = read_lstring(epg, &d->content.d77.textlen); break; case DS_COMPONENT: memcpy(&d->content.d80, epg->bin + epg->offset, 6); epg->offset += 6; d->content.d80.text = string_to_end(epg, d, 6, &d->content.d80.textlen); break; case DS_USER_DEFINED: d->content.d137.text = read_lstring(epg, &d->content.d137.textlen); memcpy(d->content.d137.lang, epg->bin + epg->offset, 3); epg->offset += 3; d->content.d137.warning = string_to_end(epg, d, 4 + d->content.d137.textlen, &d->content.d137.warninglen); break; case DS_CONTENT_IDENTIFIER: { unsigned int end = epg->offset + d->len; d->content.d118.i = 0; while (epg->offset < end) { struct crid *crid = &d->content.d118.crids[d->content.d118.i]; memcpy(crid, epg->bin + epg->offset, 1); epg->offset++; crid->cridlen = crid->ref = 0; switch (crid->location) { case 0: crid->crid = read_lstring(epg, &crid->cridlen); break; case 1: crid->ref = _swap16((uint16_t)epg->bin[epg->offset]); /* Not safe to use post increment in macro */ epg->offset++; break; default: printf("Unknown CRID location - %d\n", crid->location); } if (d->content.d118.i++ >= 3) { printf("Too many content IDs.\n"); exit(0); } } break; } default: printf("Default descriptor: %d\n", d->tag); case DS_LINKAGE: case DS_CONTENT: case DS_PRIVATE_DATA_SPECIFIER: case DS_FTA_CONTENT_MGMT: d->content.unknown.text = string_to_end(epg, d, 0, &d->content.unknown.textlen); break; } } inline void skip_descriptor(struct epg *epg, struct descriptor *d) { epg->offset += d->len; } void free_descriptor(struct descriptor *d) { if (d->loaded) { switch (d->tag) { case DS_SHORT_EVENT: if (d->content.d77.name) free(d->content.d77.name); if (d->content.d77.text) free(d->content.d77.text); break; case DS_COMPONENT: if (d->content.d80.text) free(d->content.d80.text); break; case DS_USER_DEFINED: if (d->content.d137.text) free(d->content.d137.text); if (d->content.d137.warning) free(d->content.d137.warning); break; case DS_CONTENT_IDENTIFIER: { int i; for (i = 0; i < d->content.d118.i; i++) { struct crid *crid = &d->content.d118.crids[i]; if (crid->cridlen) free(crid->crid); } break; } default: if (d->content.unknown.text) free(d->content.unknown.text); break; } } free(d); } char * descriptor_name(struct descriptor *d) { switch (d->tag) { case DS_LINKAGE: return "linkage"; case DS_SHORT_EVENT: return "short event"; case DS_COMPONENT: return "component"; case DS_CONTENT: return "content"; case DS_PRIVATE_DATA_SPECIFIER: return "private data spec."; case DS_CONTENT_IDENTIFIER: return "content id"; case DS_FTA_CONTENT_MGMT: return "content mgmt"; case DS_USER_DEFINED: return "user defined"; default: return "Unknown"; } return "Unknown"; } void dump_descriptor(struct descriptor *d, int content) { printf("Descriptor header:\n"); printf(" %30s: %#x [%d] (%s)\n", "descriptor", d->tag, d->tag, descriptor_name(d)); DUMPINT(d, len); if (!content || !d->loaded) return; switch (d->tag) { case DS_SHORT_EVENT: DUMPNSTR(d, content.d77.lang, 3); DUMPINT(d, content.d77.namelen); DUMPHEX(d, content.d77.name, d->content.d77.namelen); DUMPINT(d, content.d77.textlen); DUMPHEX(d, content.d77.text, d->content.d77.textlen); break; case DS_COMPONENT: DUMPINT(d, content.d80.stream_content); DUMPINT(d, content.d80.reserved); DUMPINT(d, content.d80.type); DUMPINT(d, content.d80.tag); DUMPNSTR(d, content.d80.lang, 3); if (d->content.d80.textlen) DUMPHEX(d, content.d80.text, d->content.d80.textlen); break; case DS_USER_DEFINED: DUMPINT(d, content.d137.textlen); DUMPNSTR(d, content.d137.lang, 3); DUMPHEX(d, content.d137.text, d->content.d137.textlen); DUMPHEX(d, content.d137.warning, d->content.d137.warninglen); break; case DS_CONTENT_IDENTIFIER: { int i; DUMPINT(d, content.d118.i); for (i = 0; i < d->content.d118.i; i++) { struct crid *crid = &d->content.d118.crids[i]; DUMPINT(crid, location); DUMPINT(crid, type); DUMPINT(crid, cridlen); if (crid->cridlen) DUMPHEX(crid, crid, crid->cridlen); DUMPINT(crid, ref); } break; } default: if (d->content.unknown.textlen) DUMPHEX(d, content.unknown.text, d->content.unknown.textlen); break; } }