#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "extensions.h"
#include "nitroarc.h"
static int print_members(nitroarc_t *narc, const char *format, bool header);
extern int tool_list(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_members(&narc, opts->format, !opts->no_header)
|| EXIT_SUCCESS;
free(data);
return errc;
}
static int print_members_markdown(nitroarc_t *narc, bool header, bool named);
static int print_members_csv(nitroarc_t *narc, bool header, bool named);
typedef struct fmtfunc fmtfunc_t;
struct fmtfunc {
const char *id;
int (*func)(nitroarc_t *narc, bool header, bool named);
};
static const fmtfunc_t handlers[] = {
{ "markdown", print_members_markdown },
{ "csv", print_members_csv },
{ 0 },
};
static int print_members(nitroarc_t *narc, const char *format, bool header) {
if (format == NULL) return print_members_markdown(narc, header, narc->named);
const fmtfunc_t *candidate = &handlers[0];
while (candidate->func != NULL) {
if (strcmp(format, candidate->id) == 0) break;
candidate++;
}
if (candidate->func == NULL) {
progerr("unrecognized format '%s'", format);
return PROGRAM_EGENERAL;
}
return candidate->func(narc, header, narc->named);
}
static inline ptrdiff_t ptrdiff(const void *_l, const void *_r) {
const unsigned char *l = _l;
const unsigned char *r = _r;
return l - r;
}
#define HEADER_MARKDOWN_1 "| Image Offset (rel) | Image Offset (abs) | Image Size (bytes) |\n"
#define HEADER_MARKDOWN_2 "| -----------------: | -----------------: | -----------------: |"
#define HEADER_MARKDOWN_INDEX "| Index | File Type " HEADER_MARKDOWN_1 \
"| :---- | --------- " HEADER_MARKDOWN_2
#define HEADER_MARKDOWN_NAME " | Path " HEADER_MARKDOWN_1 \
" | :--- " HEADER_MARKDOWN_2
#define printf_members(narc, format, ...) \
do { \
for (uint16_t i = 0; i < narc->nfiles && i < 0xF000; i++) { \
int errc = nitroarc_geti(narc, i, (void **)&mdata, &msize); \
if (errc) { \
progerr("%s", nitroarc_errs(errc)); \
return PROGRAM_ELIBERROR; \
} \
\
nitroarc_nameof(narc, i, mname, sizeof(mname)); \
printf(format, __VA_ARGS__); \
} \
} while (0)
static int print_members_markdown(nitroarc_t *narc, bool header, bool named) {
const void *mdata = NULL;
uint32_t msize = 0;
char mname[4096] = { 0 };
size_t max_namelen = 0;
if (named) {
for (uint16_t i = 0; i < narc->nfiles && i < 0xF000; i++) {
int errc = nitroarc_nameof(narc, i, mname, sizeof(mname));
if (errc) {
progerr("%s", nitroarc_errs(errc));
return PROGRAM_ELIBERROR;
}
size_t namelen = strlen(mname);
max_namelen = max_namelen < namelen ? namelen : max_namelen;
}
if (header) {
printf("| %-*s %s", (int)max_namelen, "Path", HEADER_MARKDOWN_1);
printf("| :");
for (size_t i = 0; i < max_namelen - 1; i++) putc('-', stdout);
printf(" %s\n", HEADER_MARKDOWN_2);
}
printf_members(
narc,
"| %-*s | 0x%08X | 0x%08X | %10u |\n",
(int)max_namelen,
mname,
(uint32_t)ptrdiff(mdata, narc->fimg.data),
(uint32_t)ptrdiff(mdata, narc->head),
msize
);
return NITROARC_ESUCCESS;
}
if (header) puts(HEADER_MARKDOWN_INDEX);
printf_members(
narc,
"| %5d | %-9s | 0x%08X | 0x%08X | %10u |\n",
i,
guess_extension(mdata)->ext,
(uint32_t)ptrdiff(mdata, narc->fimg.data),
(uint32_t)ptrdiff(mdata, narc->head),
msize
);
return NITROARC_ESUCCESS;
}
#define HEADER_CSV "Image Offset (rel),Image Offset (abs),Image Size (bytes)"
#define HEADER_CSV_INDEX "Index,File Type" HEADER_CSV
#define HEADER_CSV_NAME "Name," HEADER_CSV
static int print_members_csv(nitroarc_t *narc, bool header, bool named) {
char mname[4096] = { 0 };
const void *mdata = NULL;
uint32_t msize = 0;
if (named) {
if (header) puts(HEADER_CSV_NAME);
printf_members(
narc,
"%s,0x%08X,0x%08X,%u\n",
mname,
(uint32_t)ptrdiff(mdata, narc->fimg.data),
(uint32_t)ptrdiff(mdata, narc->head),
msize
);
return NITROARC_ESUCCESS;
}
if (header) puts(HEADER_CSV_INDEX);
printf_members(
narc,
"%d,%s,0x%08X,0x%08X,%u\n",
i,
guess_extension(mdata)->ext,
(uint32_t)ptrdiff(mdata, narc->fimg.data),
(uint32_t)ptrdiff(mdata, narc->head),
msize
);
return NITROARC_ESUCCESS;
}