#include #include #include static const char codechars[] = "ABCDEFHILSTUbdhn"; static double videopos[65536]; static short nibble_count[65536][16]; static int xvalue(char c) { if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'A' && c <= 'F') return c + 10 - 'A'; else if (c >= 'a' && c <= 'f') return c + 10 - 'a'; else return 0; } static int parse_logfile(const char* name) { FILE* logfile; char lines[7][64]; int i, j, v, guess, best, addr; int vscore[16]; int lastaddr = 0; double lastvpos; logfile = fopen(name, "r"); if (!logfile) { perror(name); return 1; } while (fgets(lines[0], sizeof(lines[0]), logfile)) { if (lines[0][0] == '(') { sscanf(lines[0], "(%lf)", &lastvpos); } if (lines[0][0] == '?' || isxdigit(lines[0][0])) { for (i = 1; i < 7; i++) { if (!fgets(lines[i], sizeof(lines[0]), logfile)) { fclose(logfile); fprintf(stderr, "premature EOF\n"); return 1; } } /* determine address, 4 bits at a time */ addr = 0; for (j = 0; j < 4; j++) { for (i = 0; i < 16; i++) vscore[i] = 0; vscore[(lastaddr >> (4 * j)) % 16] = 2; vscore[((lastaddr + 6) >> (4 * j)) % 16] = 2; for (i = 0; i < 7; i++) { if (isxdigit(lines[i][3 - j])) { guess = (xvalue(lines[i][3 - j]) + 15 * ((addr + i * 6) >> (4 * j))); vscore[guess % 16]++; } } best = 0; for (i = 0; i < 16; i++) { if (vscore[i] >= vscore[best]) { best = i; } } if (vscore[best] >= 4) addr |= (best << (4 * j)); else break; } if (j < 4) { fprintf(stderr, "*** After %04X: unable to determine address\n", lastaddr); continue; } if (addr != lastaddr && addr != lastaddr + 6) fprintf(stderr, "*** After %04X: continuing at %04X\n", lastaddr, addr); lastaddr = addr; videopos[addr] = lastvpos; for (i = 0; i < 7; i++) { for (j = 0; j < 12; j++) { if (lines[i][j + 4] >= '0' && lines[i][j + 4] <= '9') v = lines[i][j + 4] - '0'; else if (lines[i][j + 4] >= 'A' && lines[i][j + 4] <= 'F') v = lines[i][j + 4] - 'A' + 10; else continue; nibble_count[(addr * 2 + i * 12 + j) & 0xffff][v]++; } } } } fclose(logfile); return 0; } static int guess_nibble(int nibaddr) { int j, total, max, maxj, mcount; short *c = nibble_count[nibaddr]; total = max = maxj = 0; mcount = 1; for (j = 0; j < 16; j++) { if (c[j] > max) { max = c[j]; maxj = j; mcount = 1; } else if (c[j] == max) mcount++; total += c[j]; } if (max < 5 || mcount != 1 || max < ((3 * total) / 4)) return -1; for (j = 0; j < 16; j++) if (c[j] != max && c[j] >= max / 4) return -1; return maxj; } int main(int argc, char** argv) { FILE* binfile; char cmdbuf[1024]; int i, j, k, addr, bnum; int prev = 0; int started_display = 0; if (argc < 2 || argc > 4) { fprintf(stderr, "Usage: %s log-file [bin-file] [video-file]\n", argv[0]); return 1; } for (i = 0; i < 65536; i++) videopos[i] = 0.0; if (parse_logfile(argv[1])) return 1; if (argc > 2) { binfile = fopen(argv[2], "wb"); if (!binfile) { perror(argv[2]); return 1; } for (i = 0; i < 65536; i++) { j = guess_nibble(i); if (j == -1) { printf("\nUnable to determine value at %04X (%s).\n", i / 2, i % 2 ? "ls" : "ms"); printf("Please locate the indicated line in the video file,\n" "and type the correct character below.\n "); if (i < 0x400) addr = 0x8000 + i / 2; else addr = i / 2; bnum = addr % 6; addr -= bnum; if (argc > 3 && videopos[addr - 18] >= 1.0) { snprintf(cmdbuf, sizeof(cmdbuf), "ffmpeg -ss %g -i %s -an -vframes 1" " -vcodec ppm /tmp/81-collect-tmp.ppm 2> /dev/null", videopos[addr - 18], argv[3]); system(cmdbuf); if (!started_display) { snprintf(cmdbuf, sizeof(cmdbuf), "display -update 1 /tmp/81-collect-tmp.ppm &"); system(cmdbuf); started_display = 1; } } for (k = 12; k >= 0; k -= 4) putchar(codechars[(addr >> k) % 16]); for (k = 0; k < 12; k++) { j = guess_nibble((addr * 2 + k) & 0xffff); if (k == bnum * 2 + (i % 2)) putchar('*'); else if (j == -1) putchar('?'); else putchar(codechars[j]); } printf("\n "); for (k = 0; k < bnum * 2 + (i % 2); k++) putchar(' '); printf("^\n\n"); do { printf("> "); do { k = getchar(); } while (k == '\n' || k == '\r'); if (argc > 3 && videopos[addr - 18] >= 1.0) { if (k == '>') { videopos[addr - 18]++; snprintf(cmdbuf, sizeof(cmdbuf), "ffmpeg -ss %g -i %s -an -vframes 1" " -vcodec ppm /tmp/81-collect-tmp.ppm 2> /dev/null", videopos[addr - 18], argv[3]); system(cmdbuf); } else if (k == '<') { videopos[addr - 18]--; snprintf(cmdbuf, sizeof(cmdbuf), "ffmpeg -ss %g -i %s -an -vframes 1" " -vcodec ppm /tmp/81-collect-tmp.ppm 2> /dev/null", videopos[addr - 18], argv[3]); system(cmdbuf); } } for (j = 0; j < 16; j++) if (codechars[j] == k) break; } while (j == 16); } if (i % 2) { fputc(prev | j, binfile); } else { prev = j << 4; } } fclose(binfile); } else { for (i = 0; i < 65536; i++) { printf("%04X ", (i / 2)); j = guess_nibble(i); if (j == -1) printf("??? "); else printf("(%X) ", j); for (j = 0; j < 16; j++) { for (k = 0; k < nibble_count[i][j]; k++) { printf("%X", j); } } putchar('\n'); } } return 0; }