#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "nitroarc.h"
static int print_metadata(const nitroarc_t *narc, const options_t *opts);
extern int tool_metadata(const options_t *opts) {
if (opts->file == NULL) {
progerr(PROGRAM_NOFILE);
progerr(PROGRAM_HELP, opts->name);
return EXIT_FAILURE;
}
nitroarc_t narc = { 0 };
char *data = NULL;
size_t size = 0;
int errc = load_file(opts->file, &data, &size)
|| read_archive(data, size, &narc)
|| print_metadata(&narc, opts)
|| EXIT_SUCCESS;
free(data);
return errc;
}
static int print_metadata_markdown(const nitroarc_t *narc, bool header);
static int print_metadata_csv(const nitroarc_t *narc, bool header);
typedef struct fmtfunc fmtfunc_t;
struct fmtfunc {
const char *id;
int (*func)(const nitroarc_t *narc, bool header);
};
static const fmtfunc_t handlers[] = {
{ "markdown", print_metadata_markdown },
{ "csv", print_metadata_csv },
{ 0 },
};
static int print_metadata(const nitroarc_t *narc, const options_t *opts) {
bool header = !opts->no_header;
if (opts->format == NULL) return print_metadata_markdown(narc, header);
const fmtfunc_t *candidate = &handlers[0];
while (candidate->func != NULL) {
if (strcmp(opts->format, candidate->id) == 0) break;
candidate++;
}
if (candidate->func == NULL) {
progerr("unrecognized format '%s'", opts->format);
return PROGRAM_EGENERAL;
}
return candidate->func(narc, header);
}
#define putf printf
#define HEADER_MARKDOWN "| Section | Size (bytes) | Header Offset (abs) | Data Offset (abs) | Entry Count |\n" \
"| :------ | -----------: | ------------------: | ----------------: | ----------: |"
#define ROW_MARKDOWN "| %s | %10u | 0x%08X | 0x%08X | %5u |\n"
static int print_metadata_markdown(const nitroarc_t *narc, bool header) {
const nitroarc_fatb_t *fatb = &narc->fatb;
const nitroarc_fntb_t *fntb = &narc->fntb;
const nitroarc_fimg_t *fimg = &narc->fimg;
if (header) puts(HEADER_MARKDOWN);
putf(ROW_MARKDOWN, "NARC", narc->size, 0, fatb->ofs_head, 3);
putf(ROW_MARKDOWN, "FATB", fatb->size, fatb->ofs_head, fatb->ofs_data, narc->nfiles);
putf(ROW_MARKDOWN, "FNTB", fntb->size, fntb->ofs_head, fntb->ofs_data, narc->ndirs);
putf(ROW_MARKDOWN, "FIMG", fimg->size, fimg->ofs_head, fimg->ofs_data, narc->nfiles);
return PROGRAM_ENONE;
}
#define HEADER_CSV "Section,Size (bytes),Header Offset (abs),Data Offset (abs),Entry Count"
#define ROW_CSV "%s,%u,0x%08X,0x%08X,%u\n"
static int print_metadata_csv(const nitroarc_t *narc, bool header) {
const nitroarc_fatb_t *fatb = &narc->fatb;
const nitroarc_fntb_t *fntb = &narc->fntb;
const nitroarc_fimg_t *fimg = &narc->fimg;
if (header) puts(HEADER_CSV);
putf(ROW_CSV, "NARC", narc->size, 0, fatb->ofs_head, 3);
putf(ROW_CSV, "FATB", fatb->size, fatb->ofs_head, fatb->ofs_data, narc->nfiles);
putf(ROW_CSV, "FNTB", fntb->size, fntb->ofs_head, fntb->ofs_data, narc->ndirs);
putf(ROW_CSV, "FIMG", fimg->size, fimg->ofs_head, fimg->ofs_data, narc->nfiles);
return PROGRAM_ENONE;
}