fxsdk/fxgxa/dump.c
Lephenixnoir 50997a8b75
very crude Windows build (WIP): disable fxlink TUI, gdb bridge
There is no direct replacement for poll() in the Windows API, so I'm
gonna disable the fxlink TUI for now and maybe later figure out how to
do something equivalent, even if more brute-forcey.
2024-09-14 07:26:56 +02:00

275 lines
7.5 KiB
C

#include <stdio.h>
#include <string.h>
#include <endianness.h>
#include <fxgxa.h>
#include <g1a.h>
/* check_g1a(): Check validity of a g1a control or fixed field
This function checks a single field of a g1a header (depending on the value
of @test, from 0 up) and returns:
* 0 if the field is valid
* 1 if there is a minor error (wrong fixed-byte entry)
* 2 if there is a major error (like not a g1a, bad checksum, etc)
* -1 if the value of @test is out of bounds
It produces a description of the check in @status (even if the test is
passed); the string should have room for at least 81 bytes.
@test Test number
@g1a G1A file being manipulated
@size File size
@status Array row, at least 81 bytes free */
#define m(msg, ...) sprintf(status, msg, ##__VA_ARGS__)
static int check_g1a(int test, struct g1a const *g1a, size_t size,char *status)
{
struct g1a_header const *h = &g1a->header;
uint8_t const *raw = (void *)h;
uint16_t sum;
uint8_t ctrl;
switch(test)
{
case 0:
m("Signature \"USBPower\" \"########\"");
strncpy(status + 28, h->magic, 8);
return strncmp(h->magic, "USBPower", 8) ? 2:0;
case 1:
m("MCS Type 0xf3 0x%02x", h->mcs_type);
return (h->mcs_type != 0xf3) ? 2:0;
case 2:
m("Sequence 1 0x0010001000 0x%02x%02x%02x%02x%02x",
h->seq1[0], h->seq1[1], h->seq1[2], h->seq1[3], h->seq1[4]);
return memcmp((const char *)h->seq1, "\x00\x10\x00\x10\x00",
5) ? 1:0;
case 3:
ctrl = raw[0x13] + 0x41;
m("Control 1 0x%02x 0x%02x", ctrl, h->control1);
return (h->control1 != ctrl) ? 2:0;
case 4:
m("Sequence 2 0x01 0x%02x", h->seq2);
return (h->seq2 != 0x01) ? 1:0;
case 5:
m("File size 1 %-8lu %u", (unsigned long)size,
be32toh(h->filesize_be1));
return (be32toh(h->filesize_be1) != size) ? 2:0;
case 6:
ctrl = raw[0x13] + 0xb8;
m("Control 2 0x%02x 0x%02x", ctrl, h->control2);
return (h->control2 != ctrl) ? 2:0;
case 7:
sum = checksum_g1a(g1a, size);
m("Checksum 0x%02x 0x%02x", sum,
be16toh(h->checksum));
return (be16toh(h->checksum) != sum) ? 2:0;
case 8:
m("File size 2 %-8lu %u", (unsigned long)size,
be32toh(h->filesize_be2));
return (be32toh(h->filesize_be2) != size) ? 2:0;
default:
return -1;
}
}
/* unknown(): Dump the contents of an unknown field */
static void unknown(uint8_t const *data, size_t offset, size_t size)
{
printf(" 0x%03zx %-4zd 0x", offset, size);
for(size_t i = 0; i < size; i++) printf("%02x", data[offset + i]);
printf("\n");
}
/* field(): Print a potentially not NUL-terminated text field */
static void field(const char *field, size_t size)
{
for(size_t i = 0; i < size && field[i]; i++) putchar(field[i]);
printf("\n");
}
void dump_g1a(struct g1a const *g1a, size_t size)
{
struct g1a_header const *header = &g1a->header;
uint8_t const *raw = (void *)header;
/* Checks for g1a files */
char status[81];
int ret=0, passed=0;
printf("G1A signature checks:\n\n");
printf(" Sta. Field Expected Value\n");
for(int test = 0; ret >= 0; test++)
{
ret = check_g1a(test, g1a, size, status);
passed += !ret;
if(ret < 0) break;
printf(" %s %s\n", ret ? "FAIL" : "OK ", status);
}
printf("\nFields with unknown meanings:\n\n");
printf(" Offset Size Value\n");
unknown(raw, 0x015, 1);
unknown(raw, 0x018, 6);
unknown(raw, 0x028, 3);
unknown(raw, 0x02c, 4);
unknown(raw, 0x03a, 2);
unknown(raw, 0x04a, 2);
unknown(raw, 0x1d0, 4);
unknown(raw, 0x1dc, 20);
unknown(raw, 0x1f4, 12);
printf("\nApplication metadata:\n\n");
printf(" Program name: ");
field(header->name, 8);
printf(" Internal name: ");
field(header->internal, 8);
printf(" Version: ");
field(header->version, 10);
printf(" Build date: ");
field(header->date, 14);
printf("\nProgram icon:\n\n");
icon_print_1(header->icon, 30, 17);
}
/* See check_g3a() for a description */
static int check_g3a(int test, struct g3a const *g3a, size_t size,char *status)
{
struct g3a_header const *h = &g3a->header;
uint8_t const *raw = (void *)h;
uint16_t sum;
uint32_t sum2;
uint8_t ctrl;
switch(test)
{
case 0:
m("Signature \"USBPower\" \"########\"");
strncpy(status + 28, h->magic, 8);
return strncmp(h->magic, "USBPower", 8) ? 2:0;
case 1:
m("MCS Type 0x2c 0x%02x", h->mcs_type);
return (h->mcs_type != 0x2c) ? 2:0;
case 2:
m("Sequence 1 0x0010001000 0x%02x%02x%02x%02x%02x",
h->seq1[0], h->seq1[1], h->seq1[2], h->seq1[3], h->seq1[4]);
return memcmp((const char *)h->seq1, "\x00\x01\x00\x01\x00",
5) ? 1:0;
case 3:
ctrl = raw[0x13] + 0x41;
m("Control 1 0x%02x 0x%02x", ctrl, h->control1);
return (h->control1 != ctrl) ? 2:0;
case 4:
m("Sequence 2 0x01 0x%02x", h->seq2);
return (h->seq2 != 0x01) ? 1:0;
case 5:
m("File size 1 %-8lu %u", (unsigned long)size,
be32toh(h->filesize_be1));
return (be32toh(h->filesize_be1) != size) ? 2:0;
case 6:
ctrl = raw[0x13] + 0xb8;
m("Control 2 0x%02x 0x%02x", ctrl, h->control2);
return (h->control2 != ctrl) ? 2:0;
case 7:
sum = checksum_g3a(g3a, size);
m("Checksum 0x%02x 0x%02x", sum,
be16toh(h->checksum));
return (be16toh(h->checksum) != sum) ? 2:0;
case 8:
m("File size 2 %-8lu %u", (unsigned long)size - 0x7004,
be32toh(h->filesize_be2));
return (be32toh(h->filesize_be2) != size - 0x7004) ? 2:0;
case 9:
sum2 = checksum_g3a_2(g3a, size);
m("Checksum 2 0x%08x 0x%08x", sum2,
be32toh(h->checksum_2));
return (be32toh(h->checksum_2) != sum2) ? 2:0;
case 10:
m("File size 1 %-8lu %u", (unsigned long)size,
be32toh(h->filesize_be3));
return (be32toh(h->filesize_be3) != size) ? 2:0;
case 11:
sum2 = checksum_g3a_2(g3a, size);
uint32_t footer = be32toh(*(uint32_t *)((void *)g3a+size-4));
m("Footer 0x%08x 0x%08x", sum2, footer);
return (footer != sum2) ? 2:0;
default:
return -1;
}
}
void dump_g3a(struct g3a const *g3a, size_t size)
{
struct g3a_header const *header = &g3a->header;
uint8_t const *raw = (void *)header;
/* Checks for g3a files */
char status[81];
int ret=0, passed=0;
printf("G3A signature checks:\n\n");
printf(" Sta. Field Expected Value\n");
for(int test = 0; ret >= 0; test++)
{
ret = check_g3a(test, g3a, size, status);
passed += !ret;
if(ret < 0) break;
printf(" %s %s\n", ret ? "FAIL" : "OK ", status);
}
printf("\nFields with unknown meanings:\n\n");
printf(" Offset Size Value\n");
unknown(raw, 0x015, 1);
unknown(raw, 0x018, 6);
unknown(raw, 0x026, 8);
unknown(raw, 0x032, 14);
unknown(raw, 0x050, 12);
unknown(raw, 0x12c, 4);
unknown(raw, 0x13a, 2);
unknown(raw, 0x14a, 38);
printf(" 0x590 2348 ");
bool is_zeros = true;
for(int i = 0; i < 2348; i++)
if(raw[0x590+i] != 0) is_zeros =1;
printf(is_zeros ? "<All zeros>\n" : "<Not shown (non-zero)>\n");
printf("\nApplication metadata:\n\n");
printf(" Program name: ");
field(header->name, 16);
printf(" Internal name: ");
field(header->internal, 11);
printf(" Version: ");
field(header->version, 10);
printf(" Build date: ");
field(header->date, 14);
printf(" Filename: ");
field(header->filename, 324);
printf("\nUnselected program icon:\n\n");
icon_print_16(header->icon_uns, 92, 64);
printf("\nSelected program icon:\n\n");
icon_print_16(header->icon_sel, 92, 64);
printf("\n");
}
void dump(void *gxa, size_t size)
{
if(is_g1a(gxa))
return dump_g1a(gxa, size);
if(is_g3a(gxa))
return dump_g3a(gxa, size);
}