FreeCalypso > hg > freecalypso-reveng
view miscprog/grokdsn.c @ 382:4307b57229d3
miscprog: tone-convert written, compiles
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 10 Nov 2021 00:04:12 +0000 |
parents | 805e99848aea |
children |
line wrap: on
line source
/* * We have TI's Leonardo reference schematics in the form of 3 different PDF * versions and an OrCAD DSN file corresponding to one of them. The latter * appears (based on a cursory strings(1) inspection) to contain more * juicy information than is present in the PDF prints. We need to extract * as much of this information as we can in order to replicate the lost * Leonardo board as closely as possible. * * The top level structure of this DSN file appears to be Microsoft CDF. * Therefore, I shall begin by parsing this "archive" structure and * extracting the individual files contained therein, in an effort to gain * more insight as to what goes with what than can be gleaned from strings(1) * on the raw DSN file. This hack-utility is my CDF parser written for * this specific purpose. */ #include <sys/types.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdio.h> #include <stdint.h> #include <endian.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <strings.h> #define HEADER_MFAT_ENTRIES 109 struct cdf_header { u_char magic[8]; u_char uid[16]; uint16_t fmt_minor; uint16_t fmt_major; uint16_t byte_order; uint16_t sector_size; uint16_t subsec_size; u_char rsvd1[10]; uint32_t fat_sectors; uint32_t dir_start; u_char rsvd2[4]; uint32_t min_large_file; uint32_t subfat_start; uint32_t subfat_sectors; uint32_t mfat_start; uint32_t mfat_sectors; uint32_t fat_secids[HEADER_MFAT_ENTRIES]; }; struct dir_entry { uint16_t uni_name[32]; uint16_t name_len; u_char type; u_char color; uint32_t left_child; uint32_t right_child; uint32_t subtree_dirid; u_char uid[16]; u_char user_flags[4]; u_char time_creat[8]; u_char time_lastmod[8]; uint32_t content_secid; uint32_t content_bytes; u_char rsvd[4]; }; char *dsnfilename; u_char *filemapping; struct cdf_header *cdf_header; unsigned total_sectors, fat_nsectors; #define MAX_DIR_SECTORS 64 unsigned dir_nsectors, dir_secids[MAX_DIR_SECTORS]; open_and_mmap_file() { int fd; struct stat st; fd = open(dsnfilename, O_RDONLY); if (fd < 0) { perror(dsnfilename); exit(1); } fstat(fd, &st); if (!S_ISREG(st.st_mode)) { fprintf(stderr, "error: %s is not a regular file\n", dsnfilename); exit(1); } if (st.st_size < 512) { fprintf(stderr, "error: %s is shorter than 512 bytes\n", dsnfilename); exit(1); } if (st.st_size % 512) { fprintf(stderr, "error: %s is not a multiple of 512 bytes\n", dsnfilename); exit(1); } filemapping = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (filemapping == MAP_FAILED) { perror("mmap"); exit(1); } close(fd); cdf_header = (struct cdf_header *) filemapping; total_sectors = st.st_size / 512 - 1; return(0); } dump_cdf_header() { printf("Magic: %02X %02X %02X %02X %02X %02X %02X %02X\n", cdf_header->magic[0], cdf_header->magic[1], cdf_header->magic[2], cdf_header->magic[3], cdf_header->magic[4], cdf_header->magic[5], cdf_header->magic[6], cdf_header->magic[7]); printf("Format version: %04X.%04X\n", le16toh(cdf_header->fmt_major), le16toh(cdf_header->fmt_minor)); printf("Sector / subsector shift: %u / %u\n", le16toh(cdf_header->sector_size), le16toh(cdf_header->subsec_size)); printf("Total FAT sectors: %u\n", le32toh(cdf_header->fat_sectors)); printf("Directory start sector: %u\n", le32toh(cdf_header->dir_start)); printf("File size threshold: %u\n", le32toh(cdf_header->min_large_file)); return(0); } u_char * get_sector_ptr(secid) unsigned secid; { if (secid > total_sectors) { fprintf(stderr, "error: request for sector #%u; we only have %u in total\n", secid, total_sectors); exit(1); } return filemapping + (secid + 1) * 512; } init_fat_access() { fat_nsectors = le32toh(cdf_header->fat_sectors); if (fat_nsectors > HEADER_MFAT_ENTRIES) { fprintf(stderr, "error: large FAT not supported\n"); exit(1); } return(0); } u_char * get_fat_sector(fat_sec_no) unsigned fat_sec_no; { unsigned secid; if (fat_sec_no > fat_nsectors) { fprintf(stderr, "error: request for FAT sector #%u; we only have %u in total\n", fat_sec_no, fat_nsectors); exit(1); } secid = le32toh(cdf_header->fat_secids[fat_sec_no]); return get_sector_ptr(secid); } int32_t get_fat_entry(entry_no) unsigned entry_no; { unsigned fat_sec_no, entry_in_sec; uint32_t *fat_sector; fat_sec_no = entry_no / 128; entry_in_sec = entry_no % 128; fat_sector = (uint32_t *) get_fat_sector(fat_sec_no); return le32toh(fat_sector[entry_in_sec]); } dump_fat_chain(sarg) char *sarg; { int i, n; init_fat_access(); i = atoi(sarg); while (i >= 0) { n = get_fat_entry(i); printf("FAT[%d] = %d\n", i, n); i = n; } return(0); } locate_dir_sectors() { int sec, next, num; sec = le32toh(cdf_header->dir_start); for (num = 0; sec >= 0; sec = next) { if (num >= MAX_DIR_SECTORS) { fprintf(stderr, "error: MAX_DIR_SECTORS exceeded\n"); exit(1); } dir_secids[num++] = sec; next = get_fat_entry(sec); } dir_nsectors = num; return(0); } u_char * get_dir_sector(dir_sec_no) unsigned dir_sec_no; { unsigned secid; if (dir_sec_no > dir_nsectors) { fprintf(stderr, "error: request for dir sector #%u; we only have %u in total\n", dir_sec_no, dir_nsectors); exit(1); } secid = dir_secids[dir_sec_no]; return get_sector_ptr(secid); } struct dir_entry * get_dir_entry(dirid) unsigned dirid; { unsigned dir_sec_no, entry_in_sec; struct dir_entry *dir_sector; dir_sec_no = dirid / 4; entry_in_sec = dirid % 4; dir_sector = (struct dir_entry *) get_dir_sector(dir_sec_no); return dir_sector + entry_in_sec; } dump_dir_entry(rec, indent) struct dir_entry *rec; { int i, u; for (i = indent; i; i--) putchar(' '); for (i = 0; i < 32; i++) { u = le16toh(rec->uni_name[i]); if (u == 0) break; if (u >= ' ' && u <= '~') putchar(u); else printf("<%04X>", u); } printf(" (type %02X, length %u)\n", rec->type, rec->content_bytes); return(0); } dump_dir_level(dirid, indent) unsigned dirid; { struct dir_entry *rec; int32_t ndir; rec = get_dir_entry(dirid); ndir = le32toh(rec->left_child); if (ndir >= 0) dump_dir_level(ndir, indent); dump_dir_entry(rec, indent); ndir = le32toh(rec->subtree_dirid); if (ndir >= 0) dump_dir_level(ndir, indent + 2); ndir = le32toh(rec->right_child); if (ndir >= 0) dump_dir_level(ndir, indent); return(0); } dump_dir_tree() { init_fat_access(); locate_dir_sectors(); dump_dir_level(0, 0); return(0); } main(argc, argv) char **argv; { if (sizeof(struct cdf_header) != 512) { fprintf(stderr, "error: struct cdf_header is misdefined\n"); exit(1); } if (sizeof(struct dir_entry) != 128) { fprintf(stderr, "error: struct dir_entry is misdefined\n"); exit(1); } if (argc < 3) { fprintf(stderr, "usage: %s binfile.dsn <op> [args]\n", argv[0]); exit(1); } dsnfilename = argv[1]; open_and_mmap_file(); if (!strcmp(argv[2], "hdr")) return dump_cdf_header(); if (!strcmp(argv[2], "fatchain")) return dump_fat_chain(argv[3]); if (!strcmp(argv[2], "ls")) return dump_dir_tree(); fprintf(stderr, "error: \"%s\" is not a recognized command\n", argv[2]); exit(1); }