mirror of
https://github.com/zeldaret/oot.git
synced 2024-12-01 15:26:01 +00:00
204 lines
6 KiB
C
204 lines
6 KiB
C
/**
|
|
* SPDX-FileCopyrightText: Copyright (C) 2024 ZeldaRET
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "xml.h"
|
|
#include "aifc.h"
|
|
#include "samplebank.h"
|
|
#include "util.h"
|
|
|
|
NORETURN static void
|
|
usage(const char *progname)
|
|
{
|
|
fprintf(stderr, "Usage: %s [--matching] [--makedepend <out.d>] <in.xml> <out.s>\n", progname);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
static uint8_t match_buf[BUG_BUF_SIZE];
|
|
const char *filename = NULL;
|
|
xmlDocPtr document;
|
|
const char *outfilename = NULL;
|
|
const char *mdfilename = NULL;
|
|
FILE *mdfile;
|
|
FILE *outf;
|
|
samplebank sb;
|
|
uint8_t *match_buf_ptr;
|
|
size_t match_buf_pos;
|
|
bool matching = false;
|
|
|
|
// parse args
|
|
|
|
#define arg_error(fmt, ...) \
|
|
do { \
|
|
fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
|
|
usage(argv[0]); \
|
|
} while (0)
|
|
|
|
int argn = 0;
|
|
for (int i = 1; i < argc; i++) {
|
|
if (argv[i][0] == '-') {
|
|
// Optional args
|
|
|
|
if (strequ(argv[i], "--matching")) {
|
|
if (matching)
|
|
arg_error("Received --matching option twice");
|
|
|
|
matching = true;
|
|
continue;
|
|
}
|
|
if (strequ(argv[i], "--makedepend")) {
|
|
if (mdfilename != NULL)
|
|
arg_error("Received --makedepend option twice");
|
|
if (i + 1 == argc)
|
|
arg_error("--makedepend missing required argument");
|
|
|
|
mdfilename = argv[++i];
|
|
continue;
|
|
}
|
|
arg_error("Unknown option \"%s\"", argv[i]);
|
|
} else {
|
|
// Required args
|
|
|
|
switch (argn) {
|
|
case 0:
|
|
filename = argv[i];
|
|
break;
|
|
case 1:
|
|
outfilename = argv[i];
|
|
break;
|
|
default:
|
|
arg_error("Unknown positional argument \"%s\"", argv[i]);
|
|
break;
|
|
}
|
|
argn++;
|
|
}
|
|
}
|
|
if (argn != 2)
|
|
arg_error("Not enough positional arguments");
|
|
|
|
#undef arg_error
|
|
|
|
// open xml
|
|
document = xmlReadFile(filename, NULL, XML_PARSE_NONET);
|
|
if (document == NULL)
|
|
return EXIT_FAILURE;
|
|
|
|
// parse xml
|
|
read_samplebank_xml(&sb, document);
|
|
|
|
// open output asm file
|
|
outf = fopen(outfilename, "w");
|
|
if (outf == NULL)
|
|
error("Unable to open output file [%s] for writing", outfilename);
|
|
|
|
// open output dep file if applicable
|
|
if (mdfilename != NULL) {
|
|
mdfile = fopen(mdfilename, "w");
|
|
if (mdfile == NULL)
|
|
error("Unable to open dependency file [%s] for writing", mdfilename);
|
|
|
|
fprintf(mdfile, "%s: \\\n %s", outfilename, filename);
|
|
}
|
|
|
|
// write output
|
|
|
|
fprintf(outf,
|
|
// clang-format off
|
|
".rdata" "\n"
|
|
".balign 16" "\n"
|
|
"\n"
|
|
".global %s_Start" "\n"
|
|
"%s_Start:" "\n"
|
|
"$start:" "\n",
|
|
// clang-format on
|
|
sb.name, sb.name);
|
|
|
|
// original tool appears to have a buffer clearing bug involving a buffer sized BUG_BUF_SIZE
|
|
match_buf_ptr = (matching) ? match_buf : NULL;
|
|
match_buf_pos = 0;
|
|
|
|
for (size_t i = 0; i < sb.num_samples; i++) {
|
|
const char *name = sb.sample_names[i];
|
|
const char *path = sb.sample_paths[i];
|
|
bool is_sample = sb.is_sample[i];
|
|
|
|
if (mdfilename != NULL)
|
|
fprintf(mdfile, " \\\n %s", path);
|
|
|
|
if (!is_sample) {
|
|
// blob
|
|
fprintf(outf,
|
|
// clang-format off
|
|
"\n"
|
|
"# BLOB %s" "\n"
|
|
"\n"
|
|
".incbin \"%s\"" "\n"
|
|
"\n"
|
|
".balign 16" "\n"
|
|
"\n",
|
|
// clang-format on
|
|
name, path);
|
|
continue;
|
|
}
|
|
|
|
// aifc sample
|
|
fprintf(outf,
|
|
// clang-format off
|
|
"\n"
|
|
"# SAMPLE %lu" "\n"
|
|
"\n"
|
|
".global %s_%s_Abs" "\n"
|
|
"%s_%s_Abs:" "\n"
|
|
".global %s_%s_Off" "\n"
|
|
".set %s_%s_Off, . - $start" "\n"
|
|
"\n",
|
|
// clang-format on
|
|
i, sb.name, name, sb.name, name, sb.name, name, sb.name, name);
|
|
|
|
aifc_data aifc;
|
|
aifc_read(&aifc, path, match_buf_ptr, &match_buf_pos);
|
|
|
|
fprintf(outf, ".incbin \"%s\", 0x%lX, 0x%lX\n", path, aifc.ssnd_offset, aifc.ssnd_size);
|
|
|
|
if (matching && sb.buffer_bug && i == sb.num_samples - 1) {
|
|
// emplace garbage
|
|
size_t end = ALIGN16(match_buf_pos);
|
|
|
|
fprintf(outf, "\n# Garbage data from buffer bug\n");
|
|
for (; match_buf_pos < end; match_buf_pos++)
|
|
fprintf(outf, ".byte 0x%02X\n", match_buf[match_buf_pos]);
|
|
} else {
|
|
fputs("\n.balign 16\n", outf);
|
|
}
|
|
|
|
aifc_dispose(&aifc);
|
|
}
|
|
|
|
if (mdfilename != NULL) {
|
|
fputs("\n", mdfile);
|
|
fclose(mdfile);
|
|
}
|
|
|
|
fprintf(outf,
|
|
// clang-format off
|
|
".global %s_Size" "\n"
|
|
".set %s_Size, . - $start" "\n",
|
|
// clang-format on
|
|
sb.name, sb.name);
|
|
|
|
fclose(outf);
|
|
xmlFreeDoc(document);
|
|
return EXIT_SUCCESS;
|
|
}
|