apply clang-format to tool sources

This commit is contained in:
Henny022p
2021-11-23 09:31:09 +01:00
parent 5f41468ba8
commit dee773da4a
54 changed files with 5581 additions and 6826 deletions
Executable → Regular
+85 -93
View File
@@ -35,12 +35,12 @@
*/
#ifndef HUGE_VAL
#ifdef HUGE
#define INFINITE_VALUE HUGE
#define NAN_VALUE HUGE
#define INFINITE_VALUE HUGE
#define NAN_VALUE HUGE
#endif
#else
#define INFINITE_VALUE HUGE_VAL
#define NAN_VALUE HUGE_VAL
#define INFINITE_VALUE HUGE_VAL
#define NAN_VALUE HUGE_VAL
#endif
/*
@@ -62,111 +62,103 @@
/*
* Write IEEE Extended Precision Numbers
*/
void
ieee754_write_extended(double in, uint8_t* out)
{
int sgn, exp, shift;
double fraction, t;
unsigned int lexp, hexp;
unsigned long low, high;
void ieee754_write_extended(double in, uint8_t* out) {
int sgn, exp, shift;
double fraction, t;
unsigned int lexp, hexp;
unsigned long low, high;
if (in == 0.0) {
memset(out, 0, 10);
return;
}
if (in < 0.0) {
in = fabs(in);
sgn = 1;
} else
sgn = 0;
if (in == 0.0) {
memset(out, 0, 10);
return;
}
if (in < 0.0) {
in = fabs(in);
sgn = 1;
} else
sgn = 0;
fraction = frexp(in, &exp);
fraction = frexp(in, &exp);
if (exp == 0 || exp > 16384) {
if (exp > 16384) /* infinite value */
low = high = 0;
else {
low = 0x80000000;
high = 0;
}
exp = 32767;
goto done;
}
fraction = ldexp(fraction, 32);
t = floor(fraction);
low = (unsigned long) t;
fraction -= t;
t = floor(ldexp(fraction, 32));
high = (unsigned long) t;
if (exp == 0 || exp > 16384) {
if (exp > 16384) /* infinite value */
low = high = 0;
else {
low = 0x80000000;
high = 0;
}
exp = 32767;
goto done;
}
fraction = ldexp(fraction, 32);
t = floor(fraction);
low = (unsigned long)t;
fraction -= t;
t = floor(ldexp(fraction, 32));
high = (unsigned long)t;
/* Convert exponents < -16382 to -16382 (then they will be
* stored as -16383) */
if (exp < -16382) {
shift = 0 - exp - 16382;
high >>= shift;
high |= (low << (32 - shift));
low >>= shift;
exp = -16382;
}
exp += 16383 - 1; /* bias */
/* Convert exponents < -16382 to -16382 (then they will be
* stored as -16383) */
if (exp < -16382) {
shift = 0 - exp - 16382;
high >>= shift;
high |= (low << (32 - shift));
low >>= shift;
exp = -16382;
}
exp += 16383 - 1; /* bias */
done:
lexp = ((unsigned int) exp) >> 8;
hexp = ((unsigned int) exp) & 0xFF;
lexp = ((unsigned int)exp) >> 8;
hexp = ((unsigned int)exp) & 0xFF;
/* big endian */
out[0] = ((uint8_t) sgn) << 7;
out[0] |= (uint8_t) lexp;
out[1] = (uint8_t) hexp;
out[2] = (uint8_t) (low >> 24);
out[3] = (uint8_t) ((low >> 16) & 0xFF);
out[4] = (uint8_t) ((low >> 8) & 0xFF);
out[5] = (uint8_t) (low & 0xFF);
out[6] = (uint8_t) (high >> 24);
out[7] = (uint8_t) ((high >> 16) & 0xFF);
out[8] = (uint8_t) ((high >> 8) & 0xFF);
out[9] = (uint8_t) (high & 0xFF);
/* big endian */
out[0] = ((uint8_t)sgn) << 7;
out[0] |= (uint8_t)lexp;
out[1] = (uint8_t)hexp;
out[2] = (uint8_t)(low >> 24);
out[3] = (uint8_t)((low >> 16) & 0xFF);
out[4] = (uint8_t)((low >> 8) & 0xFF);
out[5] = (uint8_t)(low & 0xFF);
out[6] = (uint8_t)(high >> 24);
out[7] = (uint8_t)((high >> 16) & 0xFF);
out[8] = (uint8_t)((high >> 8) & 0xFF);
out[9] = (uint8_t)(high & 0xFF);
return;
return;
}
/*
* Read IEEE Extended Precision Numbers
*/
double
ieee754_read_extended(uint8_t* in)
{
int sgn, exp;
unsigned long low, high;
double out;
double ieee754_read_extended(uint8_t* in) {
int sgn, exp;
unsigned long low, high;
double out;
/* Extract the components from the big endian buffer */
sgn = (int) (in[0] >> 7);
exp = ((int) (in[0] & 0x7F) << 8) | ((int) in[1]);
low = (((unsigned long) in[2]) << 24)
| (((unsigned long) in[3]) << 16)
| (((unsigned long) in[4]) << 8) | (unsigned long) in[5];
high = (((unsigned long) in[6]) << 24)
| (((unsigned long) in[7]) << 16)
| (((unsigned long) in[8]) << 8) | (unsigned long) in[9];
/* Extract the components from the big endian buffer */
sgn = (int)(in[0] >> 7);
exp = ((int)(in[0] & 0x7F) << 8) | ((int)in[1]);
low = (((unsigned long)in[2]) << 24) | (((unsigned long)in[3]) << 16) | (((unsigned long)in[4]) << 8) |
(unsigned long)in[5];
high = (((unsigned long)in[6]) << 24) | (((unsigned long)in[7]) << 16) | (((unsigned long)in[8]) << 8) |
(unsigned long)in[9];
if (exp == 0 && low == 0 && high == 0)
return (sgn ? -0.0 : 0.0);
if (exp == 0 && low == 0 && high == 0)
return (sgn ? -0.0 : 0.0);
switch (exp) {
case 32767:
if (low == 0 && high == 0)
return (sgn ? -INFINITE_VALUE : INFINITE_VALUE);
else
return (sgn ? -NAN_VALUE : NAN_VALUE);
default:
exp -= 16383; /* unbias exponent */
switch (exp) {
case 32767:
if (low == 0 && high == 0)
return (sgn ? -INFINITE_VALUE : INFINITE_VALUE);
else
return (sgn ? -NAN_VALUE : NAN_VALUE);
default:
exp -= 16383; /* unbias exponent */
}
}
out = ldexp((double)low, -31 + exp);
out += ldexp((double)high, -63 + exp);
out = ldexp((double) low, -31 + exp);
out += ldexp((double) high, -63 + exp);
return (sgn ? -out : out);
return (sgn ? -out : out);
}
Executable → Regular
+621 -710
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
#include "offsets.h"
OffsetCalculator::OffsetCalculator(std::filesystem::path outputFile, int baseOffset): baseOffset(baseOffset) {
OffsetCalculator::OffsetCalculator(std::filesystem::path outputFile, int baseOffset) : baseOffset(baseOffset) {
output = std::ofstream(outputFile);
}
+2 -2
View File
@@ -6,11 +6,11 @@
class OffsetCalculator {
public:
public:
OffsetCalculator(std::filesystem::path offsetsFile, int baseOffset);
void addAsset(int start, std::string symbol);
private:
private:
std::ofstream output;
int baseOffset;
};
Executable → Regular
+37 -65
View File
@@ -25,27 +25,24 @@
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do \
{ \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#else
#define FATAL_ERROR(format, ...) \
do \
{ \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#endif // _MSC_VER
unsigned char *ReadWholeFile(char *path, int *size)
{
FILE *fp = fopen(path, "rb");
unsigned char* ReadWholeFile(char* path, int* size) {
FILE* fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
@@ -54,7 +51,7 @@ unsigned char *ReadWholeFile(char *path, int *size)
*size = ftell(fp);
unsigned char *buffer = malloc(*size);
unsigned char* buffer = malloc(*size);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
@@ -69,33 +66,26 @@ unsigned char *ReadWholeFile(char *path, int *size)
return buffer;
}
int ExtractData(unsigned char *buffer, int offset, int size)
{
switch (size)
{
case 1:
return buffer[offset];
case 2:
return (buffer[offset + 1] << 8)
| buffer[offset];
case 4:
return (buffer[offset + 3] << 24)
| (buffer[offset + 2] << 16)
| (buffer[offset + 1] << 8)
| buffer[offset];
default:
FATAL_ERROR("Invalid size passed to ExtractData.\n");
int ExtractData(unsigned char* buffer, int offset, int size) {
switch (size) {
case 1:
return buffer[offset];
case 2:
return (buffer[offset + 1] << 8) | buffer[offset];
case 4:
return (buffer[offset + 3] << 24) | (buffer[offset + 2] << 16) | (buffer[offset + 1] << 8) | buffer[offset];
default:
FATAL_ERROR("Invalid size passed to ExtractData.\n");
}
}
int main(int argc, char **argv)
{
int main(int argc, char** argv) {
if (argc < 3)
FATAL_ERROR("Usage: bin2c INPUT_FILE VAR_NAME [OPTIONS...]\n");
int fileSize;
unsigned char *buffer = ReadWholeFile(argv[1], &fileSize);
char *var_name = argv[2];
unsigned char* buffer = ReadWholeFile(argv[1], &fileSize);
char* var_name = argv[2];
int col = 1;
int pad = 0;
int size = 1;
@@ -103,28 +93,22 @@ int main(int argc, char **argv)
bool isStatic = false;
bool isDecimal = false;
for (int i = 3; i < argc; i++)
{
if (!strcmp(argv[i], "-col"))
{
for (int i = 3; i < argc; i++) {
if (!strcmp(argv[i], "-col")) {
i++;
if (i >= argc)
FATAL_ERROR("Missing argument after '-col'.\n");
col = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-pad"))
{
} else if (!strcmp(argv[i], "-pad")) {
i++;
if (i >= argc)
FATAL_ERROR("Missing argument after '-pad'.\n");
pad = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-size"))
{
} else if (!strcmp(argv[i], "-size")) {
i++;
if (i >= argc)
@@ -134,22 +118,14 @@ int main(int argc, char **argv)
if (size != 1 && size != 2 && size != 4)
FATAL_ERROR("Size must be 1, 2, or 4.\n");
}
else if (!strcmp(argv[i], "-signed"))
{
} else if (!strcmp(argv[i], "-signed")) {
isSigned = true;
isDecimal = true;
}
else if (!strcmp(argv[i], "-static"))
{
} else if (!strcmp(argv[i], "-static")) {
isStatic = true;
}
else if (!strcmp(argv[i], "-decimal"))
{
} else if (!strcmp(argv[i], "-decimal")) {
isDecimal = true;
}
else
{
} else {
FATAL_ERROR("Unrecognized option '%s'.\n", argv[i]);
}
}
@@ -174,23 +150,19 @@ int main(int argc, char **argv)
int count = fileSize / size;
int offset = 0;
for (int i = 0; i < count; i++)
{
for (int i = 0; i < count; i++) {
if (i % col == 0)
printf("\n ");
int data = ExtractData(buffer, offset, size);
offset += size;
if (isDecimal)
{
if (isDecimal) {
if (isSigned)
printf("%*d, ", pad, data);
else
printf("%*uu, ", pad, data);
}
else
{
} else {
printf("%#*xu, ", pad, data);
}
}
Executable → Regular
+2356 -2590
View File
File diff suppressed because it is too large Load Diff
Executable → Regular
+119 -103
View File
@@ -21,7 +21,8 @@
Please report all bugs and problems through the bug tracker at
"http://sourceforge.net/tracker/?group_id=114505&atid=668551".
"$Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/tools/gba/gbatools/gbafix.c,v 1.2 2008-07-30 17:12:51 wntrmute Exp $"
"$Header: /lvm/shared/ds/ds/cvs/devkitpro-cvsbackup/tools/gba/gbatools/gbafix.c,v 1.2 2008-07-30 17:12:51 wntrmute
Exp $"
*/
//---------------------------------------------------------------------------------
@@ -51,49 +52,45 @@
#include <stdint.h>
#include "elf.h"
#define VER "1.07"
#define ARGV argv[arg]
#define VALUE (ARGV+2)
#define NUMBER strtoul(VALUE, NULL, 0)
#define VER "1.07"
#define ARGV argv[arg]
#define VALUE (ARGV + 2)
#define NUMBER strtoul(VALUE, NULL, 0)
typedef struct
{
uint32_t start_code; // B instruction
uint8_t logo[0xA0-0x04]; // logo data
uint8_t title[0xC]; // game title name
uint32_t game_code; //
uint16_t maker_code; //
uint8_t fixed; // 0x96
uint8_t unit_code; // 0x00
uint8_t device_type; // 0x00
uint8_t unused[7]; //
uint8_t game_version; // 0x00
uint8_t complement; // 800000A0..800000BC
uint16_t checksum; // 0x0000
typedef struct {
uint32_t start_code; // B instruction
uint8_t logo[0xA0 - 0x04]; // logo data
uint8_t title[0xC]; // game title name
uint32_t game_code; //
uint16_t maker_code; //
uint8_t fixed; // 0x96
uint8_t unit_code; // 0x00
uint8_t device_type; // 0x00
uint8_t unused[7]; //
uint8_t game_version; // 0x00
uint8_t complement; // 800000A0..800000BC
uint16_t checksum; // 0x0000
} Header;
Header header;
unsigned short checksum_without_header = 0;
const Header good_header =
{
const Header good_header = {
// start_code
0xEA00002E,
// logo
{ 0x24,0xFF,0xAE,0x51,0x69,0x9A,0xA2,0x21,0x3D,0x84,0x82,0x0A,0x84,0xE4,0x09,0xAD,
0x11,0x24,0x8B,0x98,0xC0,0x81,0x7F,0x21,0xA3,0x52,0xBE,0x19,0x93,0x09,0xCE,0x20,
0x10,0x46,0x4A,0x4A,0xF8,0x27,0x31,0xEC,0x58,0xC7,0xE8,0x33,0x82,0xE3,0xCE,0xBF,
0x85,0xF4,0xDF,0x94,0xCE,0x4B,0x09,0xC1,0x94,0x56,0x8A,0xC0,0x13,0x72,0xA7,0xFC,
0x9F,0x84,0x4D,0x73,0xA3,0xCA,0x9A,0x61,0x58,0x97,0xA3,0x27,0xFC,0x03,0x98,0x76,
0x23,0x1D,0xC7,0x61,0x03,0x04,0xAE,0x56,0xBF,0x38,0x84,0x00,0x40,0xA7,0x0E,0xFD,
0xFF,0x52,0xFE,0x03,0x6F,0x95,0x30,0xF1,0x97,0xFB,0xC0,0x85,0x60,0xD6,0x80,0x25,
0xA9,0x63,0xBE,0x03,0x01,0x4E,0x38,0xE2,0xF9,0xA2,0x34,0xFF,0xBB,0x3E,0x03,0x44,
0x78,0x00,0x90,0xCB,0x88,0x11,0x3A,0x94,0x65,0xC0,0x7C,0x63,0x87,0xF0,0x3C,0xAF,
0xD6,0x25,0xE4,0x8B,0x38,0x0A,0xAC,0x72,0x21,0xD4,0xF8,0x07 } ,
{ 0x24, 0xFF, 0xAE, 0x51, 0x69, 0x9A, 0xA2, 0x21, 0x3D, 0x84, 0x82, 0x0A, 0x84, 0xE4, 0x09, 0xAD, 0x11, 0x24,
0x8B, 0x98, 0xC0, 0x81, 0x7F, 0x21, 0xA3, 0x52, 0xBE, 0x19, 0x93, 0x09, 0xCE, 0x20, 0x10, 0x46, 0x4A, 0x4A,
0xF8, 0x27, 0x31, 0xEC, 0x58, 0xC7, 0xE8, 0x33, 0x82, 0xE3, 0xCE, 0xBF, 0x85, 0xF4, 0xDF, 0x94, 0xCE, 0x4B,
0x09, 0xC1, 0x94, 0x56, 0x8A, 0xC0, 0x13, 0x72, 0xA7, 0xFC, 0x9F, 0x84, 0x4D, 0x73, 0xA3, 0xCA, 0x9A, 0x61,
0x58, 0x97, 0xA3, 0x27, 0xFC, 0x03, 0x98, 0x76, 0x23, 0x1D, 0xC7, 0x61, 0x03, 0x04, 0xAE, 0x56, 0xBF, 0x38,
0x84, 0x00, 0x40, 0xA7, 0x0E, 0xFD, 0xFF, 0x52, 0xFE, 0x03, 0x6F, 0x95, 0x30, 0xF1, 0x97, 0xFB, 0xC0, 0x85,
0x60, 0xD6, 0x80, 0x25, 0xA9, 0x63, 0xBE, 0x03, 0x01, 0x4E, 0x38, 0xE2, 0xF9, 0xA2, 0x34, 0xFF, 0xBB, 0x3E,
0x03, 0x44, 0x78, 0x00, 0x90, 0xCB, 0x88, 0x11, 0x3A, 0x94, 0x65, 0xC0, 0x7C, 0x63, 0x87, 0xF0, 0x3C, 0xAF,
0xD6, 0x25, 0xE4, 0x8B, 0x38, 0x0A, 0xAC, 0x72, 0x21, 0xD4, 0xF8, 0x07 },
// title
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
// game code
0x00000000,
// maker code
@@ -105,7 +102,7 @@ const Header good_header =
// device type
0x00,
// unused
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
// game version
0x00,
// complement
@@ -122,32 +119,30 @@ char HeaderComplement()
{
int n;
char c = 0;
char *p = (char *)&header + 0xA0;
for (n=0; n<0xBD-0xA0; n++)
{
char* p = (char*)&header + 0xA0;
for (n = 0; n < 0xBD - 0xA0; n++) {
c += *p++;
}
return -(0x19+c);
return -(0x19 + c);
}
//---------------------------------------------------------------------------------
int main(int argc, char *argv[])
int main(int argc, char* argv[])
//---------------------------------------------------------------------------------
{
int arg;
char *argfile = 0;
FILE *infile;
char* argfile = 0;
FILE* infile;
int silent = 0;
int schedule_pad = 0;
int size,bit;
int size, bit;
// show syntax
if (argc <= 1)
{
printf("GBA ROM fixer v"VER" by Dark Fader / BlackThunder / WinterMute / Diegoisawesome \n");
printf("Syntax: gbafix <rom.gba> [-p] [-t[title]] [-c<game_code>] [-m<maker_code>] [-r<version>] [-d<debug>] [--silent]\n");
if (argc <= 1) {
printf("GBA ROM fixer v" VER " by Dark Fader / BlackThunder / WinterMute / Diegoisawesome \n");
printf("Syntax: gbafix <rom.gba> [-p] [-t[title]] [-c<game_code>] [-m<maker_code>] [-r<version>] [-d<debug>] "
"[--silent]\n");
printf("\n");
printf("parameters:\n");
printf(" -p Pad to next exact power of 2. No minimum size!\n");
@@ -161,15 +156,17 @@ int main(int argc, char *argv[])
}
// get filename
for (arg=1; arg<argc; arg++)
{
if (ARGV[0] != '-') { argfile=ARGV; }
if (strncmp("--silent", &ARGV[0], 7) == 0) { silent = 1; }
for (arg = 1; arg < argc; arg++) {
if (ARGV[0] != '-') {
argfile = ARGV;
}
if (strncmp("--silent", &ARGV[0], 7) == 0) {
silent = 1;
}
}
// check filename
if (!argfile)
{
if (!argfile) {
fprintf(stderr, "Filename needed!\n");
return -1;
}
@@ -178,21 +175,28 @@ int main(int argc, char *argv[])
// read file
infile = fopen(argfile, "r+b");
if (!infile) { fprintf(stderr, "Error opening input file!\n"); return -1; }
if (!infile) {
fprintf(stderr, "Error opening input file!\n");
return -1;
}
fseek(infile, sh_offset, SEEK_SET);
fread(&header, sizeof(header), 1, infile);
// elf check
Elf32_Shdr secHeader;
if (memcmp(&header, ELFMAG, 4) == 0) {
Elf32_Ehdr *elfHeader = (Elf32_Ehdr *)&header;
Elf32_Ehdr* elfHeader = (Elf32_Ehdr*)&header;
fseek(infile, elfHeader->e_shoff, SEEK_SET);
int i;
for (i = 0; i < elfHeader->e_shnum; i++) {
fread(&secHeader, sizeof(Elf32_Shdr), 1, infile);
if (secHeader.sh_type == SHT_PROGBITS && secHeader.sh_addr == elfHeader->e_entry) break;
if (secHeader.sh_type == SHT_PROGBITS && secHeader.sh_addr == elfHeader->e_entry)
break;
}
if (i == elfHeader->e_shnum) {
fprintf(stderr, "Error finding entry point!\n");
return 1;
}
if (i == elfHeader->e_shnum) { fprintf(stderr, "Error finding entry point!\n"); return 1; }
fseek(infile, secHeader.sh_offset, SEEK_SET);
sh_offset = secHeader.sh_offset;
fread(&header, sizeof(header), 1, infile);
@@ -204,82 +208,91 @@ int main(int argc, char *argv[])
memcpy(&header.device_type, &good_header.device_type, sizeof(header.device_type));
// parse command line
for (arg=1; arg<argc; arg++)
{
if (ARGV[0] == '-')
{
switch (ARGV[1])
{
case 'p': // pad
for (arg = 1; arg < argc; arg++) {
if (ARGV[0] == '-') {
switch (ARGV[1]) {
case 'p': // pad
{
schedule_pad = 1;
break;
}
case 't': // title
case 't': // title
{
char title[256];
memset(title, 0, sizeof(title));
if (VALUE[0])
{
if (VALUE[0]) {
strncpy(title, VALUE, sizeof(header.title));
}
else
{
} else {
// use filename
char s[256], *begin=s, *t; strcpy(s, argfile);
t = strrchr(s, '\\'); if (t) begin = t+1;
t = strrchr(s, '/'); if (t) begin = t+1;
t = strrchr(s, '.'); if (t) *t = 0;
char s[256], *begin = s, *t;
strcpy(s, argfile);
t = strrchr(s, '\\');
if (t)
begin = t + 1;
t = strrchr(s, '/');
if (t)
begin = t + 1;
t = strrchr(s, '.');
if (t)
*t = 0;
strncpy(title, begin, sizeof(header.title));
if (!silent) printf("%s\n",begin);
if (!silent)
printf("%s\n", begin);
}
memcpy(header.title, title, sizeof(header.title)); // copy
memcpy(header.title, title, sizeof(header.title)); // copy
break;
}
case 'c': // game code
case 'c': // game code
{
//if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; }
//header.game_code = NUMBER;
header.game_code = VALUE[0] | VALUE[1]<<8 | VALUE[2]<<16 | VALUE[3]<<24;
// if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; }
// header.game_code = NUMBER;
header.game_code = VALUE[0] | VALUE[1] << 8 | VALUE[2] << 16 | VALUE[3] << 24;
break;
}
case 'm': // maker code
case 'm': // maker code
{
//if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; }
//header.maker_code = (unsigned short)NUMBER;
header.maker_code = VALUE[0] | VALUE[1]<<8;
// if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; }
// header.maker_code = (unsigned short)NUMBER;
header.maker_code = VALUE[0] | VALUE[1] << 8;
break;
}
case 'v': // ignored, compatability with other gbafix
case 'v': // ignored, compatability with other gbafix
{
break;
}
case 'r': // version
case 'r': // version
{
if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; }
if (!VALUE[0]) {
fprintf(stderr, "Need value for %s\n", ARGV);
break;
}
header.game_version = (unsigned char)NUMBER;
break;
}
case 'd': // debug
case 'd': // debug
{
if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; }
header.logo[0x9C-0x04] = 0xA5; // debug enable
header.device_type = (unsigned char)((NUMBER & 1) << 7); // debug handler entry point
if (!VALUE[0]) {
fprintf(stderr, "Need value for %s\n", ARGV);
break;
}
header.logo[0x9C - 0x04] = 0xA5; // debug enable
header.device_type = (unsigned char)((NUMBER & 1) << 7); // debug handler entry point
break;
}
case '-': // long arguments
case '-': // long arguments
{
if (strncmp("silent", &ARGV[2], 6) == 0) { continue; }
if (strncmp("silent", &ARGV[2], 6) == 0) {
continue;
}
break;
}
default:
{
default: {
printf("Invalid option: %s\n", ARGV);
}
}
@@ -288,9 +301,9 @@ int main(int argc, char *argv[])
// update complement check & total checksum
header.complement = 0;
header.checksum = 0; // must be 0
header.checksum = 0; // must be 0
header.complement = HeaderComplement();
//header.checksum = checksum_without_header + HeaderChecksum();
// header.checksum = checksum_without_header + HeaderChecksum();
if (schedule_pad) {
if (sh_offset != 0) {
@@ -298,11 +311,13 @@ int main(int argc, char *argv[])
} else {
fseek(infile, 0, SEEK_END);
size = ftell(infile);
for (bit=31; bit>=0; bit--) if (size & (1<<bit)) break;
if (size != (1<<bit))
{
int todo = (1<<(bit+1)) - size;
while (todo--) fputc(0xFF, infile);
for (bit = 31; bit >= 0; bit--)
if (size & (1 << bit))
break;
if (size != (1 << bit)) {
int todo = (1 << (bit + 1)) - size;
while (todo--)
fputc(0xFF, infile);
}
}
}
@@ -311,7 +326,8 @@ int main(int argc, char *argv[])
fwrite(&header, sizeof(header), 1, infile);
fclose(infile);
if (!silent) printf("ROM fixed!\n");
if (!silent)
printf("ROM fixed!\n");
return 0;
}
Executable → Regular
+19 -30
View File
@@ -7,9 +7,8 @@
#include "convert_png.h"
#include "gfx.h"
static FILE *PngReadOpen(char *path, png_structp *pngStruct, png_infop *pngInfo)
{
FILE *fp = fopen(path, "rb");
static FILE* PngReadOpen(char* path, png_structp* pngStruct, png_infop* pngInfo) {
FILE* fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
@@ -45,31 +44,27 @@ static FILE *PngReadOpen(char *path, png_structp *pngStruct, png_infop *pngInfo)
return fp;
}
static unsigned char *ConvertBitDepth(unsigned char *src, int srcBitDepth, int destBitDepth, int numPixels)
{
static unsigned char* ConvertBitDepth(unsigned char* src, int srcBitDepth, int destBitDepth, int numPixels) {
// Round the number of bits up to the next 8 and divide by 8 to get the number of bytes.
int srcSize = ((numPixels * srcBitDepth + 7) & ~7) / 8;
int destSize = ((numPixels * destBitDepth + 7) & ~7) / 8;
unsigned char *output = calloc(destSize, 1);
unsigned char *dest = output;
unsigned char* output = calloc(destSize, 1);
unsigned char* dest = output;
int i;
int j;
int destBit = 8 - destBitDepth;
for (i = 0; i < srcSize; i++)
{
for (i = 0; i < srcSize; i++) {
unsigned char srcByte = src[i];
for (j = 8 - srcBitDepth; j >= 0; j -= srcBitDepth)
{
for (j = 8 - srcBitDepth; j >= 0; j -= srcBitDepth) {
unsigned char pixel = (srcByte >> j) % (1 << srcBitDepth);
if (pixel >= (1 << destBitDepth))
FATAL_ERROR("Image exceeds the maximum color value for a %ibpp image.\n", destBitDepth);
*dest |= pixel << destBit;
destBit -= destBitDepth;
if (destBit < 0)
{
if (destBit < 0) {
dest++;
destBit = 8 - destBitDepth;
}
@@ -79,12 +74,11 @@ static unsigned char *ConvertBitDepth(unsigned char *src, int srcBitDepth, int d
return output;
}
void ReadPng(char *path, struct Image *image)
{
void ReadPng(char* path, struct Image* image) {
png_structp png_ptr;
png_infop info_ptr;
FILE *fp = PngReadOpen(path, &png_ptr, &info_ptr);
FILE* fp = PngReadOpen(path, &png_ptr, &info_ptr);
int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
@@ -125,9 +119,8 @@ void ReadPng(char *path, struct Image *image)
free(row_pointers);
fclose(fp);
if (bit_depth != image->bitDepth)
{
unsigned char *src = image->pixels;
if (bit_depth != image->bitDepth) {
unsigned char* src = image->pixels;
if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && bit_depth != 8)
FATAL_ERROR("Bit depth of image must be 1, 2, 4, or 8.\n");
@@ -137,14 +130,13 @@ void ReadPng(char *path, struct Image *image)
}
}
void ReadPngPalette(char *path, struct Palette *palette)
{
void ReadPngPalette(char* path, struct Palette* palette) {
png_structp png_ptr;
png_infop info_ptr;
png_colorp colors;
int numColors;
FILE *fp = PngReadOpen(path, &png_ptr, &info_ptr);
FILE* fp = PngReadOpen(path, &png_ptr, &info_ptr);
if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE)
FATAL_ERROR("The image \"%s\" does not contain a palette.\n", path);
@@ -167,8 +159,7 @@ void ReadPngPalette(char *path, struct Palette *palette)
fclose(fp);
}
void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette)
{
void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette* palette) {
png_colorp colors = malloc(palette->numColors * sizeof(png_color));
if (colors == NULL)
@@ -185,9 +176,8 @@ void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *pale
free(colors);
}
void WritePng(char *path, struct Image *image)
{
FILE *fp = fopen(path, "wb");
void WritePng(char* path, struct Image* image) {
FILE* fp = fopen(path, "wb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
@@ -212,9 +202,8 @@ void WritePng(char *path, struct Image *image)
int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY;
png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
image->bitDepth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_set_IHDR(png_ptr, info_ptr, image->width, image->height, image->bitDepth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
if (image->hasPalette) {
SetPngPalette(png_ptr, info_ptr, &image->palette);
Executable → Regular
+3 -3
View File
@@ -5,8 +5,8 @@
#include "gfx.h"
void ReadPng(char *path, struct Image *image);
void WritePng(char *path, struct Image *image);
void ReadPngPalette(char *path, struct Palette *palette);
void ReadPng(char* path, struct Image* image);
void WritePng(char* path, struct Image* image);
void ReadPngPalette(char* path, struct Palette* palette);
#endif // CONVERT_PNG_H
Executable → Regular
+207 -218
View File
@@ -10,317 +10,306 @@
#include "util.h"
unsigned char gFontPalette[][3] = {
{0x90, 0xC8, 0xFF}, // bg (saturated blue that contrasts well with the shadow color)
{0x38, 0x38, 0x38}, // fg (dark grey)
{0xD8, 0xD8, 0xD8}, // shadow (light grey)
{0xFF, 0xFF, 0xFF} // box (white)
{ 0x90, 0xC8, 0xFF }, // bg (saturated blue that contrasts well with the shadow color)
{ 0x38, 0x38, 0x38 }, // fg (dark grey)
{ 0xD8, 0xD8, 0xD8 }, // shadow (light grey)
{ 0xFF, 0xFF, 0xFF } // box (white)
};
static void ConvertFromLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
{
unsigned int srcPixelsOffset = 0;
static void ConvertFromLatinFont(unsigned char* src, unsigned char* dest, unsigned int numRows) {
unsigned int srcPixelsOffset = 0;
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
srcPixelsOffset += 2;
}
}
}
}
srcPixelsOffset += 2;
}
}
}
}
}
static void ConvertToLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
{
unsigned int destPixelsOffset = 0;
static void ConvertToLatinFont(unsigned char* src, unsigned char* dest, unsigned int numRows) {
unsigned int destPixelsOffset = 0;
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
destPixelsOffset += 2;
}
}
}
}
destPixelsOffset += 2;
}
}
}
}
}
static void ConvertFromHalfwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
{
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
static void ConvertFromHalfwidthJapaneseFont(unsigned char* src, unsigned char* dest, unsigned int numRows) {
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
unsigned int pixelsX = column * 8;
unsigned int srcPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
unsigned int pixelsX = column * 8;
unsigned int srcPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 32) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 32) + (pixelsX / 4);
srcPixelsOffset += 2;
}
}
}
}
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
srcPixelsOffset += 2;
}
}
}
}
}
static void ConvertToHalfwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
{
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
static void ConvertToHalfwidthJapaneseFont(unsigned char* src, unsigned char* dest, unsigned int numRows) {
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
unsigned int pixelsX = column * 8;
unsigned int destPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
unsigned int pixelsX = column * 8;
unsigned int destPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i;
unsigned int srcPixelsOffset = (pixelsY * 32) + (pixelsX / 4);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i;
unsigned int srcPixelsOffset = (pixelsY * 32) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
destPixelsOffset += 2;
}
}
}
}
destPixelsOffset += 2;
}
}
}
}
}
static void ConvertFromFullwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
{
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
static void ConvertFromFullwidthJapaneseFont(unsigned char* src, unsigned char* dest, unsigned int numRows) {
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
unsigned int srcPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
unsigned int srcPixelsOffset =
512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
srcPixelsOffset += 2;
}
}
}
}
srcPixelsOffset += 2;
}
}
}
}
}
static void ConvertToFullwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
{
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
static void ConvertToFullwidthJapaneseFont(unsigned char* src, unsigned char* dest, unsigned int numRows) {
for (unsigned int row = 0; row < numRows; row++) {
for (unsigned int column = 0; column < 16; column++) {
unsigned int glyphIndex = (row * 16) + column;
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
unsigned int destPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
unsigned int destPixelsOffset =
512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
destPixelsOffset += 2;
}
}
}
}
destPixelsOffset += 2;
}
}
}
}
}
static void SetFontPalette(struct Image *image)
{
image->hasPalette = true;
static void SetFontPalette(struct Image* image) {
image->hasPalette = true;
image->palette.numColors = 4;
image->palette.numColors = 4;
for (int i = 0; i < image->palette.numColors; i++) {
image->palette.colors[i].red = gFontPalette[i][0];
image->palette.colors[i].green = gFontPalette[i][1];
image->palette.colors[i].blue = gFontPalette[i][2];
}
for (int i = 0; i < image->palette.numColors; i++) {
image->palette.colors[i].red = gFontPalette[i][0];
image->palette.colors[i].green = gFontPalette[i][1];
image->palette.colors[i].blue = gFontPalette[i][2];
}
image->hasTransparency = false;
image->hasTransparency = false;
}
void ReadLatinFont(char *path, struct Image *image)
{
int fileSize;
unsigned char *buffer = ReadWholeFile(path, &fileSize);
void ReadLatinFont(char* path, struct Image* image) {
int fileSize;
unsigned char* buffer = ReadWholeFile(path, &fileSize);
int numGlyphs = fileSize / 64;
int numGlyphs = fileSize / 64;
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
int numRows = numGlyphs / 16;
int numRows = numGlyphs / 16;
image->width = 256;
image->height = numRows * 16;
image->bitDepth = 2;
image->pixels = malloc(fileSize);
image->width = 256;
image->height = numRows * 16;
image->bitDepth = 2;
image->pixels = malloc(fileSize);
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
ConvertFromLatinFont(buffer, image->pixels, numRows);
ConvertFromLatinFont(buffer, image->pixels, numRows);
free(buffer);
free(buffer);
SetFontPalette(image);
SetFontPalette(image);
}
void WriteLatinFont(char *path, struct Image *image)
{
if (image->width != 256)
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
void WriteLatinFont(char* path, struct Image* image) {
if (image->width != 256)
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 64;
unsigned char *buffer = malloc(bufferSize);
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 64;
unsigned char* buffer = malloc(bufferSize);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
ConvertToLatinFont(image->pixels, buffer, numRows);
ConvertToLatinFont(image->pixels, buffer, numRows);
WriteWholeFile(path, buffer, bufferSize);
WriteWholeFile(path, buffer, bufferSize);
free(buffer);
free(buffer);
}
void ReadHalfwidthJapaneseFont(char *path, struct Image *image)
{
int fileSize;
unsigned char *buffer = ReadWholeFile(path, &fileSize);
void ReadHalfwidthJapaneseFont(char* path, struct Image* image) {
int fileSize;
unsigned char* buffer = ReadWholeFile(path, &fileSize);
int glyphSize = 32;
int glyphSize = 32;
if (fileSize % glyphSize != 0)
FATAL_ERROR("The file size (%d) is not a multiple of %d.\n", fileSize, glyphSize);
if (fileSize % glyphSize != 0)
FATAL_ERROR("The file size (%d) is not a multiple of %d.\n", fileSize, glyphSize);
int numGlyphs = fileSize / glyphSize;
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
int numGlyphs = fileSize / glyphSize;
int numRows = numGlyphs / 16;
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
image->width = 128;
image->height = numRows * 16;
image->bitDepth = 2;
image->pixels = malloc(fileSize);
int numRows = numGlyphs / 16;
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
image->width = 128;
image->height = numRows * 16;
image->bitDepth = 2;
image->pixels = malloc(fileSize);
ConvertFromHalfwidthJapaneseFont(buffer, image->pixels, numRows);
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
free(buffer);
ConvertFromHalfwidthJapaneseFont(buffer, image->pixels, numRows);
SetFontPalette(image);
free(buffer);
SetFontPalette(image);
}
void WriteHalfwidthJapaneseFont(char *path, struct Image *image)
{
if (image->width != 128)
FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width);
void WriteHalfwidthJapaneseFont(char* path, struct Image* image) {
if (image->width != 128)
FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width);
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 32;
unsigned char *buffer = malloc(bufferSize);
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 32;
unsigned char* buffer = malloc(bufferSize);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
ConvertToHalfwidthJapaneseFont(image->pixels, buffer, numRows);
ConvertToHalfwidthJapaneseFont(image->pixels, buffer, numRows);
WriteWholeFile(path, buffer, bufferSize);
WriteWholeFile(path, buffer, bufferSize);
free(buffer);
free(buffer);
}
void ReadFullwidthJapaneseFont(char *path, struct Image *image)
{
int fileSize;
unsigned char *buffer = ReadWholeFile(path, &fileSize);
void ReadFullwidthJapaneseFont(char* path, struct Image* image) {
int fileSize;
unsigned char* buffer = ReadWholeFile(path, &fileSize);
int numGlyphs = fileSize / 64;
int numGlyphs = fileSize / 64;
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
int numRows = numGlyphs / 16;
int numRows = numGlyphs / 16;
image->width = 256;
image->height = numRows * 16;
image->bitDepth = 2;
image->pixels = malloc(fileSize);
image->width = 256;
image->height = numRows * 16;
image->bitDepth = 2;
image->pixels = malloc(fileSize);
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
ConvertFromFullwidthJapaneseFont(buffer, image->pixels, numRows);
ConvertFromFullwidthJapaneseFont(buffer, image->pixels, numRows);
free(buffer);
free(buffer);
SetFontPalette(image);
SetFontPalette(image);
}
void WriteFullwidthJapaneseFont(char *path, struct Image *image)
{
if (image->width != 256)
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
void WriteFullwidthJapaneseFont(char* path, struct Image* image) {
if (image->width != 256)
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 64;
unsigned char *buffer = malloc(bufferSize);
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 64;
unsigned char* buffer = malloc(bufferSize);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
ConvertToFullwidthJapaneseFont(image->pixels, buffer, numRows);
ConvertToFullwidthJapaneseFont(image->pixels, buffer, numRows);
WriteWholeFile(path, buffer, bufferSize);
WriteWholeFile(path, buffer, bufferSize);
free(buffer);
free(buffer);
}
Executable → Regular
+6 -6
View File
@@ -6,11 +6,11 @@
#include <stdbool.h>
#include "gfx.h"
void ReadLatinFont(char *path, struct Image *image);
void WriteLatinFont(char *path, struct Image *image);
void ReadHalfwidthJapaneseFont(char *path, struct Image *image);
void WriteHalfwidthJapaneseFont(char *path, struct Image *image);
void ReadFullwidthJapaneseFont(char *path, struct Image *image);
void WriteFullwidthJapaneseFont(char *path, struct Image *image);
void ReadLatinFont(char* path, struct Image* image);
void WriteLatinFont(char* path, struct Image* image);
void ReadHalfwidthJapaneseFont(char* path, struct Image* image);
void WriteHalfwidthJapaneseFont(char* path, struct Image* image);
void ReadFullwidthJapaneseFont(char* path, struct Image* image);
void WriteFullwidthJapaneseFont(char* path, struct Image* image);
#endif // FONT_H
Executable → Regular
+261 -247
View File
@@ -8,337 +8,351 @@
#include "gfx.h"
#include "util.h"
#define GET_GBA_PAL_RED(x) (((x) >> 0) & 0x1F)
#define GET_GBA_PAL_GREEN(x) (((x) >> 5) & 0x1F)
#define GET_GBA_PAL_BLUE(x) (((x) >> 10) & 0x1F)
#define GET_GBA_PAL_RED(x) (((x) >> 0) & 0x1F)
#define GET_GBA_PAL_GREEN(x) (((x) >> 5) & 0x1F)
#define GET_GBA_PAL_BLUE(x) (((x) >> 10) & 0x1F)
#define SET_GBA_PAL(r, g, b) (((b) << 10) | ((g) << 5) | (r))
#define UPCONVERT_BIT_DEPTH(x) (((x) * 255) / 31)
#define UPCONVERT_BIT_DEPTH(x) (((x)*255) / 31)
#define DOWNCONVERT_BIT_DEPTH(x) ((x) / 8)
static void AdvanceMetatilePosition(int *subTileX, int *subTileY, int *metatileX, int *metatileY, int metatilesWide, int metatileWidth, int metatileHeight)
{
(*subTileX)++;
if (*subTileX == metatileWidth) {
*subTileX = 0;
(*subTileY)++;
if (*subTileY == metatileHeight) {
*subTileY = 0;
(*metatileX)++;
if (*metatileX == metatilesWide) {
*metatileX = 0;
(*metatileY)++;
}
}
}
static void AdvanceMetatilePosition(int* subTileX, int* subTileY, int* metatileX, int* metatileY, int metatilesWide,
int metatileWidth, int metatileHeight) {
(*subTileX)++;
if (*subTileX == metatileWidth) {
*subTileX = 0;
(*subTileY)++;
if (*subTileY == metatileHeight) {
*subTileY = 0;
(*metatileX)++;
if (*metatileX == metatilesWide) {
*metatileX = 0;
(*metatileY)++;
}
}
}
}
static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = metatilesWide * metatileWidth;
static void ConvertFromTiles1Bpp(unsigned char* src, unsigned char* dest, int numTiles, int metatilesWide,
int metatileWidth, int metatileHeight, bool invertColors) {
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = metatilesWide * metatileWidth;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
int destX = metatileX * metatileWidth + subTileX;
unsigned char srcPixelOctet = *src++;
unsigned char *destPixelOctet = &dest[destY * pitch + destX];
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
int destX = metatileX * metatileWidth + subTileX;
unsigned char srcPixelOctet = *src++;
unsigned char* destPixelOctet = &dest[destY * pitch + destX];
for (int k = 0; k < 8; k++) {
*destPixelOctet <<= 1;
*destPixelOctet |= (srcPixelOctet & 1) ^ invertColors;
srcPixelOctet >>= 1;
}
}
for (int k = 0; k < 8; k++) {
*destPixelOctet <<= 1;
*destPixelOctet |= (srcPixelOctet & 1) ^ invertColors;
srcPixelOctet >>= 1;
}
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth,
metatileHeight);
}
}
static void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 4;
static void ConvertFromTiles4Bpp(unsigned char* src, unsigned char* dest, int numTiles, int metatilesWide,
int metatileWidth, int metatileHeight, bool invertColors) {
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 4;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 4; k++) {
int destX = (metatileX * metatileWidth + subTileX) * 4 + k;
unsigned char srcPixelPair = *src++;
unsigned char leftPixel = srcPixelPair & 0xF;
unsigned char rightPixel = srcPixelPair >> 4;
for (int k = 0; k < 4; k++) {
int destX = (metatileX * metatileWidth + subTileX) * 4 + k;
unsigned char srcPixelPair = *src++;
unsigned char leftPixel = srcPixelPair & 0xF;
unsigned char rightPixel = srcPixelPair >> 4;
if (invertColors) {
leftPixel = 15 - leftPixel;
rightPixel = 15 - rightPixel;
}
if (invertColors) {
leftPixel = 15 - leftPixel;
rightPixel = 15 - rightPixel;
}
dest[destY * pitch + destX] = (leftPixel << 4) | rightPixel;
}
}
dest[destY * pitch + destX] = (leftPixel << 4) | rightPixel;
}
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth,
metatileHeight);
}
}
static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 8;
static void ConvertFromTiles8Bpp(unsigned char* src, unsigned char* dest, int numTiles, int metatilesWide,
int metatileWidth, int metatileHeight, bool invertColors) {
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 8;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 8; k++) {
int destX = (metatileX * metatileWidth + subTileX) * 8 + k;
unsigned char srcPixel = *src++;
for (int k = 0; k < 8; k++) {
int destX = (metatileX * metatileWidth + subTileX) * 8 + k;
unsigned char srcPixel = *src++;
if (invertColors)
srcPixel = 255 - srcPixel;
if (invertColors)
srcPixel = 255 - srcPixel;
dest[destY * pitch + destX] = srcPixel;
}
}
dest[destY * pitch + destX] = srcPixel;
}
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth,
metatileHeight);
}
}
static void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = metatilesWide * metatileWidth;
static void ConvertToTiles1Bpp(unsigned char* src, unsigned char* dest, int numTiles, int metatilesWide,
int metatileWidth, int metatileHeight, bool invertColors) {
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = metatilesWide * metatileWidth;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
int srcX = metatileX * metatileWidth + subTileX;
unsigned char srcPixelOctet = src[srcY * pitch + srcX];
unsigned char *destPixelOctet = dest++;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
int srcX = metatileX * metatileWidth + subTileX;
unsigned char srcPixelOctet = src[srcY * pitch + srcX];
unsigned char* destPixelOctet = dest++;
for (int k = 0; k < 8; k++) {
*destPixelOctet <<= 1;
*destPixelOctet |= (srcPixelOctet & 1) ^ invertColors;
srcPixelOctet >>= 1;
}
}
for (int k = 0; k < 8; k++) {
*destPixelOctet <<= 1;
*destPixelOctet |= (srcPixelOctet & 1) ^ invertColors;
srcPixelOctet >>= 1;
}
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth,
metatileHeight);
}
}
static void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 4;
static void ConvertToTiles4Bpp(unsigned char* src, unsigned char* dest, int numTiles, int metatilesWide,
int metatileWidth, int metatileHeight, bool invertColors) {
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 4;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 4; k++) {
int srcX = (metatileX * metatileWidth + subTileX) * 4 + k;
unsigned char srcPixelPair = src[srcY * pitch + srcX];
unsigned char leftPixel = srcPixelPair >> 4;
unsigned char rightPixel = srcPixelPair & 0xF;
for (int k = 0; k < 4; k++) {
int srcX = (metatileX * metatileWidth + subTileX) * 4 + k;
unsigned char srcPixelPair = src[srcY * pitch + srcX];
unsigned char leftPixel = srcPixelPair >> 4;
unsigned char rightPixel = srcPixelPair & 0xF;
if (invertColors) {
leftPixel = 15 - leftPixel;
rightPixel = 15 - rightPixel;
}
if (invertColors) {
leftPixel = 15 - leftPixel;
rightPixel = 15 - rightPixel;
}
*dest++ = (rightPixel << 4) | leftPixel;
}
}
*dest++ = (rightPixel << 4) | leftPixel;
}
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth,
metatileHeight);
}
}
static void ConvertToTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 8;
static void ConvertToTiles8Bpp(unsigned char* src, unsigned char* dest, int numTiles, int metatilesWide,
int metatileWidth, int metatileHeight, bool invertColors) {
int subTileX = 0;
int subTileY = 0;
int metatileX = 0;
int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 8;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 8; k++) {
int srcX = (metatileX * metatileWidth + subTileX) * 8 + k;
unsigned char srcPixel = src[srcY * pitch + srcX];
for (int k = 0; k < 8; k++) {
int srcX = (metatileX * metatileWidth + subTileX) * 8 + k;
unsigned char srcPixel = src[srcY * pitch + srcX];
if (invertColors)
srcPixel = 255 - srcPixel;
if (invertColors)
srcPixel = 255 - srcPixel;
*dest++ = srcPixel;
}
}
*dest++ = srcPixel;
}
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
}
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth,
metatileHeight);
}
}
void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors)
{
int tileSize = bitDepth * 8;
void ReadImage(char* path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image* image,
bool invertColors) {
int tileSize = bitDepth * 8;
int fileSize;
unsigned char *buffer = ReadWholeFile(path, &fileSize);
int fileSize;
unsigned char* buffer = ReadWholeFile(path, &fileSize);
int numTiles = fileSize / tileSize;
int numTiles = fileSize / tileSize;
int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth;
int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth;
if (tilesWidth % metatileWidth != 0)
FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth);
if (tilesWidth % metatileWidth != 0)
FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth,
metatileWidth);
if (tilesHeight % metatileHeight != 0)
FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight);
if (tilesHeight % metatileHeight != 0)
FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight,
metatileHeight);
image->width = tilesWidth * 8;
image->height = tilesHeight * 8;
image->bitDepth = bitDepth;
image->pixels = calloc(tilesWidth * tilesHeight, tileSize);
image->width = tilesWidth * 8;
image->height = tilesHeight * 8;
image->bitDepth = bitDepth;
image->pixels = calloc(tilesWidth * tilesHeight, tileSize);
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for pixels.\n");
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for pixels.\n");
int metatilesWide = tilesWidth / metatileWidth;
int metatilesWide = tilesWidth / metatileWidth;
switch (bitDepth) {
case 1:
ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break;
case 4:
ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break;
case 8:
ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break;
}
switch (bitDepth) {
case 1:
ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight,
invertColors);
break;
case 4:
ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight,
invertColors);
break;
case 8:
ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight,
invertColors);
break;
}
free(buffer);
free(buffer);
}
void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors)
{
int tileSize = bitDepth * 8;
void WriteImage(char* path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image* image,
bool invertColors) {
int tileSize = bitDepth * 8;
if (image->width % 8 != 0)
FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width);
if (image->width % 8 != 0)
FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width);
if (image->height % 8 != 0)
FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height);
if (image->height % 8 != 0)
FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height);
int tilesWidth = image->width / 8;
int tilesHeight = image->height / 8;
int tilesWidth = image->width / 8;
int tilesHeight = image->height / 8;
if (tilesWidth % metatileWidth != 0)
FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth);
if (tilesWidth % metatileWidth != 0)
FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth,
metatileWidth);
if (tilesHeight % metatileHeight != 0)
FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight);
if (tilesHeight % metatileHeight != 0)
FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight,
metatileHeight);
int maxNumTiles = tilesWidth * tilesHeight;
int maxNumTiles = tilesWidth * tilesHeight;
if (numTiles == 0)
numTiles = maxNumTiles;
else if (numTiles > maxNumTiles)
FATAL_ERROR("The specified number of tiles (%d) is greater than the maximum possible value (%d).\n", numTiles, maxNumTiles);
if (numTiles == 0)
numTiles = maxNumTiles;
else if (numTiles > maxNumTiles)
FATAL_ERROR("The specified number of tiles (%d) is greater than the maximum possible value (%d).\n", numTiles,
maxNumTiles);
int bufferSize = numTiles * tileSize;
unsigned char *buffer = malloc(bufferSize);
int bufferSize = numTiles * tileSize;
unsigned char* buffer = malloc(bufferSize);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for pixels.\n");
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for pixels.\n");
int metatilesWide = tilesWidth / metatileWidth;
int metatilesWide = tilesWidth / metatileWidth;
switch (bitDepth) {
case 1:
ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break;
case 4:
ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break;
case 8:
ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break;
}
switch (bitDepth) {
case 1:
ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight,
invertColors);
break;
case 4:
ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight,
invertColors);
break;
case 8:
ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight,
invertColors);
break;
}
WriteWholeFile(path, buffer, bufferSize);
WriteWholeFile(path, buffer, bufferSize);
free(buffer);
free(buffer);
}
void FreeImage(struct Image *image)
{
free(image->pixels);
image->pixels = NULL;
void FreeImage(struct Image* image) {
free(image->pixels);
image->pixels = NULL;
}
void ReadGbaPalette(char *path, struct Palette *palette)
{
int fileSize;
unsigned char *data = ReadWholeFile(path, &fileSize);
void ReadGbaPalette(char* path, struct Palette* palette) {
int fileSize;
unsigned char* data = ReadWholeFile(path, &fileSize);
if (fileSize % 2 != 0)
FATAL_ERROR("The file size (%d) is not a multiple of 2.\n", fileSize);
if (fileSize % 2 != 0)
FATAL_ERROR("The file size (%d) is not a multiple of 2.\n", fileSize);
palette->numColors = fileSize / 2;
palette->numColors = fileSize / 2;
for (int i = 0; i < palette->numColors; i++) {
uint16_t paletteEntry = (data[i * 2 + 1] << 8) | data[i * 2];
palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry));
palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry));
palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry));
}
for (int i = 0; i < palette->numColors; i++) {
uint16_t paletteEntry = (data[i * 2 + 1] << 8) | data[i * 2];
palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry));
palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry));
palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry));
}
free(data);
free(data);
}
void WriteGbaPalette(char *path, struct Palette *palette)
{
FILE *fp = fopen(path, "wb");
void WriteGbaPalette(char* path, struct Palette* palette) {
FILE* fp = fopen(path, "wb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
for (int i = 0; i < palette->numColors; i++) {
unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red);
unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green);
unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue);
for (int i = 0; i < palette->numColors; i++) {
unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red);
unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green);
unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue);
uint16_t paletteEntry = SET_GBA_PAL(red, green, blue);
uint16_t paletteEntry = SET_GBA_PAL(red, green, blue);
fputc(paletteEntry & 0xFF, fp);
fputc(paletteEntry >> 8, fp);
}
fputc(paletteEntry & 0xFF, fp);
fputc(paletteEntry >> 8, fp);
}
fclose(fp);
fclose(fp);
}
Executable → Regular
+19 -17
View File
@@ -7,30 +7,32 @@
#include <stdbool.h>
struct Color {
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct Palette {
struct Color colors[256];
int numColors;
struct Color colors[256];
int numColors;
};
struct Image {
int width;
int height;
int bitDepth;
unsigned char *pixels;
bool hasPalette;
struct Palette palette;
bool hasTransparency;
int width;
int height;
int bitDepth;
unsigned char* pixels;
bool hasPalette;
struct Palette palette;
bool hasTransparency;
};
void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors);
void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors);
void FreeImage(struct Image *image);
void ReadGbaPalette(char *path, struct Palette *palette);
void WriteGbaPalette(char *path, struct Palette *palette);
void ReadImage(char* path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image* image,
bool invertColors);
void WriteImage(char* path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image* image,
bool invertColors);
void FreeImage(struct Image* image);
void ReadGbaPalette(char* path, struct Palette* palette);
void WriteGbaPalette(char* path, struct Palette* palette);
#endif // GFX_H
Executable → Regular
+10 -10
View File
@@ -8,21 +8,21 @@
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#define UNUSED
#else
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define UNUSED __attribute__((__unused__))
Executable → Regular
+82 -82
View File
@@ -6,94 +6,94 @@
#include "global.h"
#include "huff.h"
static int cmp_tree(const void * a0, const void * b0) {
return ((struct HuffData *)a0)->value - ((struct HuffData *)b0)->value;
static int cmp_tree(const void* a0, const void* b0) {
return ((struct HuffData*)a0)->value - ((struct HuffData*)b0)->value;
}
typedef int (*cmpfun)(const void *, const void *);
typedef int (*cmpfun)(const void*, const void*);
int msort_r(void * data, size_t count, size_t size, cmpfun cmp, void * buffer) {
int msort_r(void* data, size_t count, size_t size, cmpfun cmp, void* buffer) {
/*
* Out-of-place mergesort (stable sort)
* Returns 1 on success, 0 on failure
*/
void * leftPtr;
void * rightPtr;
void * leftEnd;
void * rightEnd;
void* leftPtr;
void* rightPtr;
void* leftEnd;
void* rightEnd;
int i;
switch (count) {
case 0:
// Should never be here
return 0;
case 1:
// Nothing to do here
break;
case 2:
// Swap the two entries if the right one compares higher.
if (cmp(data, data + size) > 0) {
memcpy(buffer, data, size);
memcpy(data, data + size, size);
memcpy(data + size, buffer, size);
}
break;
default:
// Merge sort out-of-place.
leftPtr = data;
leftEnd = rightPtr = data + count / 2 * size;
rightEnd = data + count * size;
// Sort the left half
if (!msort_r(leftPtr, count / 2, size, cmp, buffer))
case 0:
// Should never be here
return 0;
// Sort the right half
if (!msort_r(rightPtr, count / 2 + (count & 1), size, cmp, buffer))
return 0;
case 1:
// Nothing to do here
break;
// Merge the sorted halves out of place
i = 0;
do {
if (cmp(leftPtr, rightPtr) <= 0) {
memcpy(buffer + i * size, leftPtr, size);
leftPtr += size;
} else {
memcpy(buffer + i * size, rightPtr, size);
rightPtr += size;
case 2:
// Swap the two entries if the right one compares higher.
if (cmp(data, data + size) > 0) {
memcpy(buffer, data, size);
memcpy(data, data + size, size);
memcpy(data + size, buffer, size);
}
break;
default:
// Merge sort out-of-place.
leftPtr = data;
leftEnd = rightPtr = data + count / 2 * size;
rightEnd = data + count * size;
// Sort the left half
if (!msort_r(leftPtr, count / 2, size, cmp, buffer))
return 0;
// Sort the right half
if (!msort_r(rightPtr, count / 2 + (count & 1), size, cmp, buffer))
return 0;
// Merge the sorted halves out of place
i = 0;
do {
if (cmp(leftPtr, rightPtr) <= 0) {
memcpy(buffer + i * size, leftPtr, size);
leftPtr += size;
} else {
memcpy(buffer + i * size, rightPtr, size);
rightPtr += size;
}
} while (++i < count && leftPtr < leftEnd && rightPtr < rightEnd);
// Copy the remainder
if (i < count) {
if (leftPtr < leftEnd) {
memcpy(buffer + i * size, leftPtr, leftEnd - leftPtr);
} else {
memcpy(buffer + i * size, rightPtr, rightEnd - rightPtr);
}
}
} while (++i < count && leftPtr < leftEnd && rightPtr < rightEnd);
// Copy the remainder
if (i < count) {
if (leftPtr < leftEnd) {
memcpy(buffer + i * size, leftPtr, leftEnd - leftPtr);
}
else {
memcpy(buffer + i * size, rightPtr, rightEnd - rightPtr);
}
}
// Copy the merged data back
memcpy(data, buffer, count * size);
break;
// Copy the merged data back
memcpy(data, buffer, count * size);
break;
}
return 1;
}
int msort(void * data, size_t count, size_t size, cmpfun cmp) {
void * buffer = malloc(count * size);
if (buffer == NULL) return 0;
int msort(void* data, size_t count, size_t size, cmpfun cmp) {
void* buffer = malloc(count * size);
if (buffer == NULL)
return 0;
int result = msort_r(data, count, size, cmp, buffer);
free(buffer);
return result;
}
static void write_tree(unsigned char * dest, HuffNode_t * tree, int nitems, struct BitEncoding * encoding) {
static void write_tree(unsigned char* dest, HuffNode_t* tree, int nitems, struct BitEncoding* encoding) {
/*
* The example used to guide this function encodes the tree in a
* breadth-first manner. We attempt to emulate that here.
@@ -102,7 +102,7 @@ static void write_tree(unsigned char * dest, HuffNode_t * tree, int nitems, stru
int i, j, k;
// There are (2 * nitems - 1) nodes in the binary tree. Allocate that.
HuffNode_t * traversal = calloc(2 * nitems - 1, sizeof(HuffNode_t));
HuffNode_t* traversal = calloc(2 * nitems - 1, sizeof(HuffNode_t));
if (traversal == NULL)
FATAL_ERROR("Fatal error while compressing Huff file.\n");
@@ -117,8 +117,8 @@ static void write_tree(unsigned char * dest, HuffNode_t * tree, int nitems, stru
// The index of the path is used to encode the path itself.
// Start from the most significant relevant bit and work our way down.
// Keep track of the current and previous nodes.
HuffNode_t * currNode = traversal;
HuffNode_t * parent = NULL;
HuffNode_t* currNode = traversal;
HuffNode_t* parent = NULL;
for (k = 0; k < depth; k++) {
if (currNode->header.isLeaf)
break;
@@ -159,7 +159,7 @@ static void write_tree(unsigned char * dest, HuffNode_t * tree, int nitems, stru
// Encode each node in the tree.
for (i = 0; i < 2 * nitems - 1; i++) {
HuffNode_t * currNode = traversal + i;
HuffNode_t* currNode = traversal + i;
if (currNode->header.isLeaf) {
dest[5 + i] = traversal[i].leaf.key;
} else {
@@ -174,7 +174,7 @@ static void write_tree(unsigned char * dest, HuffNode_t * tree, int nitems, stru
free(traversal);
}
static inline void write_32_le(unsigned char * dest, int * destPos, uint32_t * buff, int * buffPos) {
static inline void write_32_le(unsigned char* dest, int* destPos, uint32_t* buff, int* buffPos) {
dest[*destPos] = *buff;
dest[*destPos + 1] = *buff >> 8;
dest[*destPos + 2] = *buff >> 16;
@@ -184,7 +184,7 @@ static inline void write_32_le(unsigned char * dest, int * destPos, uint32_t * b
*buffPos = 0;
}
static inline void read_32_le(unsigned char * src, int * srcPos, uint32_t * buff) {
static inline void read_32_le(unsigned char* src, int* srcPos, uint32_t* buff) {
uint32_t tmp = src[*srcPos];
tmp |= src[*srcPos + 1] << 8;
tmp |= src[*srcPos + 2] << 16;
@@ -193,7 +193,8 @@ static inline void read_32_le(unsigned char * src, int * srcPos, uint32_t * buff
*buff = tmp;
}
static void write_bits(unsigned char * dest, int * destPos, struct BitEncoding * encoding, int value, uint32_t * buff, int * buffBits) {
static void write_bits(unsigned char* dest, int* destPos, struct BitEncoding* encoding, int value, uint32_t* buff,
int* buffBits) {
int nbits = encoding[value].nbits;
uint32_t bitstring = encoding[value].bitstring;
@@ -218,23 +219,23 @@ MAIN COMPRESSION/DECOMPRESSION ROUTINES
=======================================
*/
unsigned char * HuffCompress(unsigned char * src, int srcSize, int * compressedSize_p, int bitDepth) {
unsigned char* HuffCompress(unsigned char* src, int srcSize, int* compressedSize_p, int bitDepth) {
if (srcSize <= 0)
goto fail;
int worstCaseDestSize = 4 + (2 << bitDepth) + srcSize * 3;
unsigned char *dest = malloc(worstCaseDestSize);
unsigned char* dest = malloc(worstCaseDestSize);
if (dest == NULL)
goto fail;
int nitems = 1 << bitDepth;
HuffNode_t * freqs = calloc(nitems, sizeof(HuffNode_t));
HuffNode_t* freqs = calloc(nitems, sizeof(HuffNode_t));
if (freqs == NULL)
goto fail;
struct BitEncoding * encoding = calloc(nitems, sizeof(struct BitEncoding));
struct BitEncoding* encoding = calloc(nitems, sizeof(struct BitEncoding));
if (encoding == NULL)
goto fail;
@@ -281,16 +282,16 @@ unsigned char * HuffCompress(unsigned char * src, int srcSize, int * compressedS
goto fail;
}
HuffNode_t * tree = calloc(nitems * 2 - 1, sizeof(HuffNode_t));
HuffNode_t* tree = calloc(nitems * 2 - 1, sizeof(HuffNode_t));
if (tree == NULL)
goto fail;
// Iteratively collapse the two least frequent nodes.
HuffNode_t * endptr = freqs + nitems - 2;
HuffNode_t* endptr = freqs + nitems - 2;
for (int i = 0; i < nitems - 1; i++) {
HuffNode_t * left = freqs;
HuffNode_t * right = freqs + 1;
HuffNode_t* left = freqs;
HuffNode_t* right = freqs + 1;
tree[i * 2] = *right;
tree[i * 2 + 1] = *left;
for (int j = 0; j < nitems - i - 2; j++)
@@ -342,7 +343,7 @@ fail:
FATAL_ERROR("Fatal error while compressing Huff file.\n");
}
unsigned char * HuffDecompress(unsigned char * src, int srcSize, int * uncompressedSize_p) {
unsigned char* HuffDecompress(unsigned char* src, int srcSize, int* uncompressedSize_p) {
if (srcSize < 4)
goto fail;
@@ -352,7 +353,7 @@ unsigned char * HuffDecompress(unsigned char * src, int srcSize, int * uncompres
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
unsigned char *dest = malloc(destSize);
unsigned char* dest = malloc(destSize);
if (dest == NULL)
goto fail;
@@ -365,8 +366,7 @@ unsigned char * HuffDecompress(unsigned char * src, int srcSize, int * uncompres
uint32_t destTmp = 0;
uint32_t window;
for (;;)
{
for (;;) {
if (srcPos >= srcSize)
goto fail;
read_32_le(src, &srcPos, &window);
Executable → Regular
+9 -9
View File
@@ -4,8 +4,8 @@
union HuffNode;
struct HuffData {
unsigned value:31;
unsigned isLeaf:1;
unsigned value : 31;
unsigned isLeaf : 1;
};
struct HuffLeaf {
@@ -15,8 +15,8 @@ struct HuffLeaf {
struct HuffBranch {
struct HuffData header;
union HuffNode * left;
union HuffNode * right;
union HuffNode* left;
union HuffNode* right;
};
union HuffNode {
@@ -28,11 +28,11 @@ union HuffNode {
typedef union HuffNode HuffNode_t;
struct BitEncoding {
unsigned long long nbits:6;
unsigned long long bitstring:58;
unsigned long long nbits : 6;
unsigned long long bitstring : 58;
};
unsigned char * HuffCompress(unsigned char * buffer, int srcSize, int * compressedSize_p, int bitDepth);
unsigned char * HuffDecompress(unsigned char * buffer, int srcSize, int * uncompressedSize_p);
unsigned char* HuffCompress(unsigned char* buffer, int srcSize, int* compressedSize_p, int bitDepth);
unsigned char* HuffDecompress(unsigned char* buffer, int srcSize, int* uncompressedSize_p);
#endif //HUFF_H
#endif // HUFF_H
Executable → Regular
+15 -22
View File
@@ -24,17 +24,14 @@
#define MAX_LINE_LENGTH 11
void ReadJascPaletteLine(FILE *fp, char *line)
{
void ReadJascPaletteLine(FILE* fp, char* line) {
int c;
int length = 0;
for (;;)
{
for (;;) {
c = fgetc(fp);
if (c == '\r')
{
if (c == '\r') {
c = fgetc(fp);
if (c != '\n')
@@ -54,8 +51,7 @@ void ReadJascPaletteLine(FILE *fp, char *line)
if (c == 0)
FATAL_ERROR("NUL character in file.\n");
if (length == MAX_LINE_LENGTH)
{
if (length == MAX_LINE_LENGTH) {
line[length] = 0;
FATAL_ERROR("The line \"%s\" is too long.\n", line);
}
@@ -64,11 +60,10 @@ void ReadJascPaletteLine(FILE *fp, char *line)
}
}
void ReadJascPalette(char *path, struct Palette *palette)
{
void ReadJascPalette(char* path, struct Palette* palette) {
char line[MAX_LINE_LENGTH + 1];
FILE *fp = fopen(path, "rb");
FILE* fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open JASC-PAL file \"%s\" for reading.\n", path);
@@ -89,14 +84,14 @@ void ReadJascPalette(char *path, struct Palette *palette)
FATAL_ERROR("Failed to parse number of colors.\n");
if (palette->numColors < 1 || palette->numColors > 256)
FATAL_ERROR("%d is an invalid number of colors. The number of colors must be in the range [1, 256].\n", palette->numColors);
FATAL_ERROR("%d is an invalid number of colors. The number of colors must be in the range [1, 256].\n",
palette->numColors);
for (int i = 0; i < palette->numColors; i++)
{
for (int i = 0; i < palette->numColors; i++) {
ReadJascPaletteLine(fp, line);
char *s = line;
char *end;
char* s = line;
char* end;
int red;
int green;
@@ -154,17 +149,15 @@ void ReadJascPalette(char *path, struct Palette *palette)
fclose(fp);
}
void WriteJascPalette(char *path, struct Palette *palette)
{
FILE *fp = fopen(path, "wb");
void WriteJascPalette(char* path, struct Palette* palette) {
FILE* fp = fopen(path, "wb");
fputs("JASC-PAL\r\n", fp);
fputs("0100\r\n", fp);
fprintf(fp, "%d\r\n", palette->numColors);
for (int i = 0; i < palette->numColors; i++)
{
struct Color *color = &palette->colors[i];
for (int i = 0; i < palette->numColors; i++) {
struct Color* color = &palette->colors[i];
fprintf(fp, "%d %d %d\r\n", color->red, color->green, color->blue);
}
Executable → Regular
+2 -2
View File
@@ -3,7 +3,7 @@
#ifndef JASC_PAL_H
#define JASC_PAL_H
void ReadJascPalette(char *path, struct Palette *palette);
void WriteJascPalette(char *path, struct Palette *palette);
void ReadJascPalette(char* path, struct Palette* palette);
void WriteJascPalette(char* path, struct Palette* palette);
#endif // JASC_PAL_H
Executable → Regular
+103 -106
View File
@@ -5,149 +5,146 @@
#include "global.h"
#include "lz.h"
unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSize)
{
if (srcSize < 4)
goto fail;
unsigned char* LZDecompress(unsigned char* src, int srcSize, int* uncompressedSize) {
if (srcSize < 4)
goto fail;
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
unsigned char *dest = malloc(destSize);
unsigned char* dest = malloc(destSize);
if (dest == NULL)
goto fail;
if (dest == NULL)
goto fail;
int srcPos = 4;
int destPos = 0;
int srcPos = 4;
int destPos = 0;
for (;;) {
if (srcPos >= srcSize)
goto fail;
for (;;) {
if (srcPos >= srcSize)
goto fail;
unsigned char flags = src[srcPos++];
unsigned char flags = src[srcPos++];
for (int i = 0; i < 8; i++) {
if (flags & 0x80) {
if (srcPos + 1 >= srcSize)
goto fail;
for (int i = 0; i < 8; i++) {
if (flags & 0x80) {
if (srcPos + 1 >= srcSize)
goto fail;
int blockSize = (src[srcPos] >> 4) + 3;
int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1;
int blockSize = (src[srcPos] >> 4) + 3;
int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1;
srcPos += 2;
srcPos += 2;
int blockPos = destPos - blockDistance;
int blockPos = destPos - blockDistance;
// Some Ruby/Sapphire tilesets overflow.
if (destPos + blockSize > destSize) {
blockSize = destSize - destPos;
fprintf(stderr, "Destination buffer overflow.\n");
}
// Some Ruby/Sapphire tilesets overflow.
if (destPos + blockSize > destSize) {
blockSize = destSize - destPos;
fprintf(stderr, "Destination buffer overflow.\n");
}
if (blockPos < 0)
goto fail;
if (blockPos < 0)
goto fail;
for (int j = 0; j < blockSize; j++)
dest[destPos++] = dest[blockPos + j];
} else {
if (srcPos >= srcSize || destPos >= destSize)
goto fail;
for (int j = 0; j < blockSize; j++)
dest[destPos++] = dest[blockPos + j];
} else {
if (srcPos >= srcSize || destPos >= destSize)
goto fail;
dest[destPos++] = src[srcPos++];
}
dest[destPos++] = src[srcPos++];
}
if (destPos == destSize) {
*uncompressedSize = destSize;
return dest;
}
if (destPos == destSize) {
*uncompressedSize = destSize;
return dest;
}
flags <<= 1;
}
}
flags <<= 1;
}
}
fail:
FATAL_ERROR("Fatal error while decompressing LZ file.\n");
FATAL_ERROR("Fatal error while decompressing LZ file.\n");
}
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance)
{
if (srcSize <= 0)
goto fail;
unsigned char* LZCompress(unsigned char* src, int srcSize, int* compressedSize, const int minDistance) {
if (srcSize <= 0)
goto fail;
int worstCaseDestSize = 4 + srcSize + ((srcSize + 7) / 8);
int worstCaseDestSize = 4 + srcSize + ((srcSize + 7) / 8);
// Round up to the next multiple of four.
worstCaseDestSize = (worstCaseDestSize + 3) & ~3;
// Round up to the next multiple of four.
worstCaseDestSize = (worstCaseDestSize + 3) & ~3;
unsigned char *dest = malloc(worstCaseDestSize);
unsigned char* dest = malloc(worstCaseDestSize);
if (dest == NULL)
goto fail;
if (dest == NULL)
goto fail;
// header
dest[0] = 0x10; // LZ compression type
dest[1] = (unsigned char)srcSize;
dest[2] = (unsigned char)(srcSize >> 8);
dest[3] = (unsigned char)(srcSize >> 16);
// header
dest[0] = 0x10; // LZ compression type
dest[1] = (unsigned char)srcSize;
dest[2] = (unsigned char)(srcSize >> 8);
dest[3] = (unsigned char)(srcSize >> 16);
int srcPos = 0;
int destPos = 4;
int srcPos = 0;
int destPos = 4;
for (;;) {
unsigned char *flags = &dest[destPos++];
*flags = 0;
for (;;) {
unsigned char* flags = &dest[destPos++];
*flags = 0;
for (int i = 0; i < 8; i++) {
int bestBlockDistance = 0;
int bestBlockSize = 0;
int blockDistance = minDistance;
for (int i = 0; i < 8; i++) {
int bestBlockDistance = 0;
int bestBlockSize = 0;
int blockDistance = minDistance;
while (blockDistance <= srcPos && blockDistance <= 0x1000) {
int blockStart = srcPos - blockDistance;
int blockSize = 0;
while (blockDistance <= srcPos && blockDistance <= 0x1000) {
int blockStart = srcPos - blockDistance;
int blockSize = 0;
while (blockSize < 18
&& srcPos + blockSize < srcSize
&& src[blockStart + blockSize] == src[srcPos + blockSize])
blockSize++;
while (blockSize < 18 && srcPos + blockSize < srcSize &&
src[blockStart + blockSize] == src[srcPos + blockSize])
blockSize++;
if (blockSize > bestBlockSize) {
bestBlockDistance = blockDistance;
bestBlockSize = blockSize;
if (blockSize > bestBlockSize) {
bestBlockDistance = blockDistance;
bestBlockSize = blockSize;
if (blockSize == 18)
break;
}
if (blockSize == 18)
break;
}
blockDistance++;
}
blockDistance++;
}
if (bestBlockSize >= 3) {
*flags |= (0x80 >> i);
srcPos += bestBlockSize;
bestBlockSize -= 3;
bestBlockDistance--;
dest[destPos++] = (bestBlockSize << 4) | ((unsigned int)bestBlockDistance >> 8);
dest[destPos++] = (unsigned char)bestBlockDistance;
} else {
dest[destPos++] = src[srcPos++];
}
if (bestBlockSize >= 3) {
*flags |= (0x80 >> i);
srcPos += bestBlockSize;
bestBlockSize -= 3;
bestBlockDistance--;
dest[destPos++] = (bestBlockSize << 4) | ((unsigned int)bestBlockDistance >> 8);
dest[destPos++] = (unsigned char)bestBlockDistance;
} else {
dest[destPos++] = src[srcPos++];
}
if (srcPos == srcSize) {
// Pad to multiple of 4 bytes.
int remainder = destPos % 4;
if (srcPos == srcSize) {
// Pad to multiple of 4 bytes.
int remainder = destPos % 4;
if (remainder != 0) {
for (int i = 0; i < 4 - remainder; i++)
dest[destPos++] = 0;
}
if (remainder != 0) {
for (int i = 0; i < 4 - remainder; i++)
dest[destPos++] = 0;
}
*compressedSize = destPos;
return dest;
}
}
}
*compressedSize = destPos;
return dest;
}
}
}
fail:
FATAL_ERROR("Fatal error while compressing LZ file.\n");
FATAL_ERROR("Fatal error while compressing LZ file.\n");
}
Executable → Regular
+2 -2
View File
@@ -3,7 +3,7 @@
#ifndef LZ_H
#define LZ_H
unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSize);
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance);
unsigned char* LZDecompress(unsigned char* src, int srcSize, int* uncompressedSize);
unsigned char* LZCompress(unsigned char* src, int srcSize, int* compressedSize, const int minDistance);
#endif // LZ_H
Executable → Regular
+102 -161
View File
@@ -14,28 +14,24 @@
#include "font.h"
#include "huff.h"
struct CommandHandler
{
const char *inputFileExtension;
const char *outputFileExtension;
void(*function)(char *inputPath, char *outputPath, int argc, char **argv);
struct CommandHandler {
const char* inputFileExtension;
const char* outputFileExtension;
void (*function)(char* inputPath, char* outputPath, int argc, char** argv);
};
void ConvertGbaToPng(char *inputPath, char *outputPath, struct GbaToPngOptions *options)
{
void ConvertGbaToPng(char* inputPath, char* outputPath, struct GbaToPngOptions* options) {
struct Image image;
if (options->paletteFilePath != NULL)
{
if (options->paletteFilePath != NULL) {
ReadGbaPalette(options->paletteFilePath, &image.palette);
image.hasPalette = true;
}
else
{
} else {
image.hasPalette = false;
}
ReadImage(inputPath, options->width, options->bitDepth, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette);
ReadImage(inputPath, options->width, options->bitDepth, options->metatileWidth, options->metatileHeight, &image,
!image.hasPalette);
image.hasTransparency = options->hasTransparency;
@@ -44,22 +40,21 @@ void ConvertGbaToPng(char *inputPath, char *outputPath, struct GbaToPngOptions *
FreeImage(&image);
}
void ConvertPngToGba(char *inputPath, char *outputPath, struct PngToGbaOptions *options)
{
void ConvertPngToGba(char* inputPath, char* outputPath, struct PngToGbaOptions* options) {
struct Image image;
image.bitDepth = options->bitDepth;
ReadPng(inputPath, &image);
WriteImage(outputPath, options->numTiles, options->bitDepth, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette);
WriteImage(outputPath, options->numTiles, options->bitDepth, options->metatileWidth, options->metatileHeight,
&image, !image.hasPalette);
FreeImage(&image);
}
void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **argv)
{
char *inputFileExtension = GetFileExtension(inputPath);
void HandleGbaToPngCommand(char* inputPath, char* outputPath, int argc, char** argv) {
char* inputFileExtension = GetFileExtension(inputPath);
struct GbaToPngOptions options;
options.paletteFilePath = NULL;
options.bitDepth = inputFileExtension[0] - '0';
@@ -68,25 +63,19 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a
options.metatileWidth = 1;
options.metatileHeight = 1;
for (int i = 3; i < argc; i++)
{
char *option = argv[i];
for (int i = 3; i < argc; i++) {
char* option = argv[i];
if (strcmp(option, "-palette") == 0)
{
if (strcmp(option, "-palette") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No palette file path following \"-palette\".\n");
i++;
options.paletteFilePath = argv[i];
}
else if (strcmp(option, "-object") == 0)
{
} else if (strcmp(option, "-object") == 0) {
options.hasTransparency = true;
}
else if (strcmp(option, "-width") == 0)
{
} else if (strcmp(option, "-width") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No width following \"-width\".\n");
@@ -97,9 +86,7 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a
if (options.width < 1)
FATAL_ERROR("Width must be positive.\n");
}
else if (strcmp(option, "-mwidth") == 0)
{
} else if (strcmp(option, "-mwidth") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No metatile width value following \"-mwidth\".\n");
@@ -110,9 +97,7 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a
if (options.metatileWidth < 1)
FATAL_ERROR("metatile width must be positive.\n");
}
else if (strcmp(option, "-mheight") == 0)
{
} else if (strcmp(option, "-mheight") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No metatile height value following \"-mheight\".\n");
@@ -123,9 +108,7 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a
if (options.metatileHeight < 1)
FATAL_ERROR("metatile height must be positive.\n");
}
else
{
} else {
FATAL_ERROR("Unrecognized option \"%s\".\n", option);
}
}
@@ -136,9 +119,8 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a
ConvertGbaToPng(inputPath, outputPath, &options);
}
void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **argv)
{
char *outputFileExtension = GetFileExtension(outputPath);
void HandlePngToGbaCommand(char* inputPath, char* outputPath, int argc, char** argv) {
char* outputFileExtension = GetFileExtension(outputPath);
int bitDepth = outputFileExtension[0] - '0';
struct PngToGbaOptions options;
options.numTiles = 0;
@@ -146,12 +128,10 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a
options.metatileWidth = 1;
options.metatileHeight = 1;
for (int i = 3; i < argc; i++)
{
char *option = argv[i];
for (int i = 3; i < argc; i++) {
char* option = argv[i];
if (strcmp(option, "-num_tiles") == 0)
{
if (strcmp(option, "-num_tiles") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No number of tiles following \"-num_tiles\".\n");
@@ -162,9 +142,7 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a
if (options.numTiles < 1)
FATAL_ERROR("Number of tiles must be positive.\n");
}
else if (strcmp(option, "-mwidth") == 0)
{
} else if (strcmp(option, "-mwidth") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No metatile width value following \"-mwidth\".\n");
@@ -175,9 +153,7 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a
if (options.metatileWidth < 1)
FATAL_ERROR("metatile width must be positive.\n");
}
else if (strcmp(option, "-mheight") == 0)
{
} else if (strcmp(option, "-mheight") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No metatile height value following \"-mheight\".\n");
@@ -188,9 +164,7 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a
if (options.metatileHeight < 1)
FATAL_ERROR("metatile height must be positive.\n");
}
else
{
} else {
FATAL_ERROR("Unrecognized option \"%s\".\n", option);
}
}
@@ -198,32 +172,27 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a
ConvertPngToGba(inputPath, outputPath, &options);
}
void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandlePngToGbaPaletteCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Palette palette;
ReadPngPalette(inputPath, &palette);
WriteGbaPalette(outputPath, &palette);
}
void HandleGbaToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleGbaToJascPaletteCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Palette palette;
ReadGbaPalette(inputPath, &palette);
WriteJascPalette(outputPath, &palette);
}
void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc, char **argv)
{
void HandleJascToGbaPaletteCommand(char* inputPath, char* outputPath, int argc, char** argv) {
int numColors = 0;
for (int i = 3; i < argc; i++)
{
char *option = argv[i];
for (int i = 3; i < argc; i++) {
char* option = argv[i];
if (strcmp(option, "-num_colors") == 0)
{
if (strcmp(option, "-num_colors") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No number of colors following \"-num_colors\".\n");
@@ -234,9 +203,7 @@ void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc,
if (numColors < 1)
FATAL_ERROR("Number of colors must be positive.\n");
}
else
{
} else {
FATAL_ERROR("Unrecognized option \"%s\".\n", option);
}
}
@@ -251,8 +218,7 @@ void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc,
WriteGbaPalette(outputPath, &palette);
}
void HandleLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleLatinFontToPngCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Image image;
ReadLatinFont(inputPath, &image);
@@ -261,8 +227,7 @@ void HandleLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNU
FreeImage(&image);
}
void HandlePngToLatinFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandlePngToLatinFontCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Image image;
image.bitDepth = 2;
@@ -273,8 +238,7 @@ void HandlePngToLatinFontCommand(char *inputPath, char *outputPath, int argc UNU
FreeImage(&image);
}
void HandleHalfwidthJapaneseFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleHalfwidthJapaneseFontToPngCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Image image;
ReadHalfwidthJapaneseFont(inputPath, &image);
@@ -283,8 +247,7 @@ void HandleHalfwidthJapaneseFontToPngCommand(char *inputPath, char *outputPath,
FreeImage(&image);
}
void HandlePngToHalfwidthJapaneseFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandlePngToHalfwidthJapaneseFontCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Image image;
image.bitDepth = 2;
@@ -295,8 +258,7 @@ void HandlePngToHalfwidthJapaneseFontCommand(char *inputPath, char *outputPath,
FreeImage(&image);
}
void HandleFullwidthJapaneseFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleFullwidthJapaneseFontToPngCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Image image;
ReadFullwidthJapaneseFont(inputPath, &image);
@@ -305,8 +267,7 @@ void HandleFullwidthJapaneseFontToPngCommand(char *inputPath, char *outputPath,
FreeImage(&image);
}
void HandlePngToFullwidthJapaneseFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandlePngToFullwidthJapaneseFontCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
struct Image image;
image.bitDepth = 2;
@@ -317,17 +278,14 @@ void HandlePngToFullwidthJapaneseFontCommand(char *inputPath, char *outputPath,
FreeImage(&image);
}
void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc, char **argv)
{
void HandleLZCompressCommand(char* inputPath, char* outputPath, int argc, char** argv) {
int overflowSize = 0;
int minDistance = 2; // default, for compatibility with LZ77UnCompVram()
for (int i = 3; i < argc; i++)
{
char *option = argv[i];
for (int i = 3; i < argc; i++) {
char* option = argv[i];
if (strcmp(option, "-overflow") == 0)
{
if (strcmp(option, "-overflow") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No size following \"-overflow\".\n");
@@ -338,9 +296,7 @@ void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc, char *
if (overflowSize < 1)
FATAL_ERROR("Overflow size must be positive.\n");
}
else if (strcmp(option, "-search") == 0)
{
} else if (strcmp(option, "-search") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No size following \"-overflow\".\n");
@@ -351,9 +307,7 @@ void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc, char *
if (minDistance < 1)
FATAL_ERROR("LZ min search distance must be positive.\n");
}
else
{
} else {
FATAL_ERROR("Unrecognized option \"%s\".\n", option);
}
}
@@ -365,10 +319,10 @@ void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc, char *
// the data.
int fileSize;
unsigned char *buffer = ReadWholeFileZeroPadded(inputPath, &fileSize, overflowSize);
unsigned char* buffer = ReadWholeFileZeroPadded(inputPath, &fileSize, overflowSize);
int compressedSize;
unsigned char *compressedData = LZCompress(buffer, fileSize + overflowSize, &compressedSize, minDistance);
unsigned char* compressedData = LZCompress(buffer, fileSize + overflowSize, &compressedSize, minDistance);
compressedData[1] = (unsigned char)fileSize;
compressedData[2] = (unsigned char)(fileSize >> 8);
@@ -381,13 +335,12 @@ void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc, char *
free(compressedData);
}
void HandleLZDecompressCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleLZDecompressCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
int fileSize;
unsigned char *buffer = ReadWholeFile(inputPath, &fileSize);
unsigned char* buffer = ReadWholeFile(inputPath, &fileSize);
int uncompressedSize;
unsigned char *uncompressedData = LZDecompress(buffer, fileSize, &uncompressedSize);
unsigned char* uncompressedData = LZDecompress(buffer, fileSize, &uncompressedSize);
free(buffer);
@@ -396,13 +349,12 @@ void HandleLZDecompressCommand(char *inputPath, char *outputPath, int argc UNUSE
free(uncompressedData);
}
void HandleRLCompressCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleRLCompressCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
int fileSize;
unsigned char *buffer = ReadWholeFile(inputPath, &fileSize);
unsigned char* buffer = ReadWholeFile(inputPath, &fileSize);
int compressedSize;
unsigned char *compressedData = RLCompress(buffer, fileSize, &compressedSize);
unsigned char* compressedData = RLCompress(buffer, fileSize, &compressedSize);
free(buffer);
@@ -411,13 +363,12 @@ void HandleRLCompressCommand(char *inputPath, char *outputPath, int argc UNUSED,
free(compressedData);
}
void HandleRLDecompressCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleRLDecompressCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
int fileSize;
unsigned char *buffer = ReadWholeFile(inputPath, &fileSize);
unsigned char* buffer = ReadWholeFile(inputPath, &fileSize);
int uncompressedSize;
unsigned char *uncompressedData = RLDecompress(buffer, fileSize, &uncompressedSize);
unsigned char* uncompressedData = RLDecompress(buffer, fileSize, &uncompressedSize);
free(buffer);
@@ -426,17 +377,14 @@ void HandleRLDecompressCommand(char *inputPath, char *outputPath, int argc UNUSE
free(uncompressedData);
}
void HandleHuffCompressCommand(char *inputPath, char *outputPath, int argc, char **argv)
{
void HandleHuffCompressCommand(char* inputPath, char* outputPath, int argc, char** argv) {
int fileSize;
int bitDepth = 4;
for (int i = 3; i < argc; i++)
{
char *option = argv[i];
for (int i = 3; i < argc; i++) {
char* option = argv[i];
if (strcmp(option, "-depth") == 0)
{
if (strcmp(option, "-depth") == 0) {
if (i + 1 >= argc)
FATAL_ERROR("No size following \"-depth\".\n");
@@ -447,17 +395,15 @@ void HandleHuffCompressCommand(char *inputPath, char *outputPath, int argc, char
if (bitDepth != 4 && bitDepth != 8)
FATAL_ERROR("GBA only supports bit depth of 4 or 8.\n");
}
else
{
} else {
FATAL_ERROR("Unrecognized option \"%s\".\n", option);
}
}
unsigned char *buffer = ReadWholeFile(inputPath, &fileSize);
unsigned char* buffer = ReadWholeFile(inputPath, &fileSize);
int compressedSize;
unsigned char *compressedData = HuffCompress(buffer, fileSize, &compressedSize, bitDepth);
unsigned char* compressedData = HuffCompress(buffer, fileSize, &compressedSize, bitDepth);
free(buffer);
@@ -466,13 +412,12 @@ void HandleHuffCompressCommand(char *inputPath, char *outputPath, int argc, char
free(compressedData);
}
void HandleHuffDecompressCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
void HandleHuffDecompressCommand(char* inputPath, char* outputPath, int argc UNUSED, char** argv UNUSED) {
int fileSize;
unsigned char *buffer = ReadWholeFile(inputPath, &fileSize);
unsigned char* buffer = ReadWholeFile(inputPath, &fileSize);
int uncompressedSize;
unsigned char *uncompressedData = HuffDecompress(buffer, fileSize, &uncompressedSize);
unsigned char* uncompressedData = HuffDecompress(buffer, fileSize, &uncompressedSize);
free(buffer);
@@ -481,41 +426,37 @@ void HandleHuffDecompressCommand(char *inputPath, char *outputPath, int argc UNU
free(uncompressedData);
}
int main(int argc, char **argv)
{
int main(int argc, char** argv) {
if (argc < 3)
FATAL_ERROR("Usage: gbagfx INPUT_PATH OUTPUT_PATH [options...]\n");
struct CommandHandler handlers[] =
{
{ "1bpp", "png", HandleGbaToPngCommand },
{ "4bpp", "png", HandleGbaToPngCommand },
{ "8bpp", "png", HandleGbaToPngCommand },
{ "png", "1bpp", HandlePngToGbaCommand },
{ "png", "4bpp", HandlePngToGbaCommand },
{ "png", "8bpp", HandlePngToGbaCommand },
{ "png", "gbapal", HandlePngToGbaPaletteCommand },
{ "gbapal", "pal", HandleGbaToJascPaletteCommand },
{ "pal", "gbapal", HandleJascToGbaPaletteCommand },
{ "latfont", "png", HandleLatinFontToPngCommand },
{ "png", "latfont", HandlePngToLatinFontCommand },
{ "hwjpnfont", "png", HandleHalfwidthJapaneseFontToPngCommand },
{ "png", "hwjpnfont", HandlePngToHalfwidthJapaneseFontCommand },
{ "fwjpnfont", "png", HandleFullwidthJapaneseFontToPngCommand },
{ "png", "fwjpnfont", HandlePngToFullwidthJapaneseFontCommand },
{ NULL, "huff", HandleHuffCompressCommand },
{ NULL, "lz", HandleLZCompressCommand },
{ "huff", NULL, HandleHuffDecompressCommand },
{ "lz", NULL, HandleLZDecompressCommand },
{ NULL, "rl", HandleRLCompressCommand },
{ "rl", NULL, HandleRLDecompressCommand },
{ NULL, NULL, NULL }
};
struct CommandHandler handlers[] = { { "1bpp", "png", HandleGbaToPngCommand },
{ "4bpp", "png", HandleGbaToPngCommand },
{ "8bpp", "png", HandleGbaToPngCommand },
{ "png", "1bpp", HandlePngToGbaCommand },
{ "png", "4bpp", HandlePngToGbaCommand },
{ "png", "8bpp", HandlePngToGbaCommand },
{ "png", "gbapal", HandlePngToGbaPaletteCommand },
{ "gbapal", "pal", HandleGbaToJascPaletteCommand },
{ "pal", "gbapal", HandleJascToGbaPaletteCommand },
{ "latfont", "png", HandleLatinFontToPngCommand },
{ "png", "latfont", HandlePngToLatinFontCommand },
{ "hwjpnfont", "png", HandleHalfwidthJapaneseFontToPngCommand },
{ "png", "hwjpnfont", HandlePngToHalfwidthJapaneseFontCommand },
{ "fwjpnfont", "png", HandleFullwidthJapaneseFontToPngCommand },
{ "png", "fwjpnfont", HandlePngToFullwidthJapaneseFontCommand },
{ NULL, "huff", HandleHuffCompressCommand },
{ NULL, "lz", HandleLZCompressCommand },
{ "huff", NULL, HandleHuffDecompressCommand },
{ "lz", NULL, HandleLZDecompressCommand },
{ NULL, "rl", HandleRLCompressCommand },
{ "rl", NULL, HandleRLDecompressCommand },
{ NULL, NULL, NULL } };
char *inputPath = argv[1];
char *outputPath = argv[2];
char *inputFileExtension = GetFileExtension(inputPath);
char *outputFileExtension = GetFileExtension(outputPath);
char* inputPath = argv[1];
char* outputPath = argv[2];
char* inputFileExtension = GetFileExtension(inputPath);
char* outputFileExtension = GetFileExtension(outputPath);
if (inputFileExtension == NULL)
FATAL_ERROR("Input file \"%s\" has no extension.\n", inputPath);
@@ -523,11 +464,11 @@ int main(int argc, char **argv)
if (outputFileExtension == NULL)
FATAL_ERROR("Output file \"%s\" has no extension.\n", outputPath);
for (int i = 0; handlers[i].function != NULL; i++)
{
if ((handlers[i].inputFileExtension == NULL || strcmp(handlers[i].inputFileExtension, inputFileExtension) == 0)
&& (handlers[i].outputFileExtension == NULL || strcmp(handlers[i].outputFileExtension, outputFileExtension) == 0))
{
for (int i = 0; handlers[i].function != NULL; i++) {
if ((handlers[i].inputFileExtension == NULL ||
strcmp(handlers[i].inputFileExtension, inputFileExtension) == 0) &&
(handlers[i].outputFileExtension == NULL ||
strcmp(handlers[i].outputFileExtension, outputFileExtension) == 0)) {
handlers[i].function(inputPath, outputPath, argc, argv);
return 0;
}
Executable → Regular
+1 -1
View File
@@ -6,7 +6,7 @@
#include <stdbool.h>
struct GbaToPngOptions {
char *paletteFilePath;
char* paletteFilePath;
int bitDepth;
bool hasTransparency;
int width;
Executable → Regular
+17 -32
View File
@@ -5,14 +5,13 @@
#include "global.h"
#include "rl.h"
unsigned char *RLDecompress(unsigned char *src, int srcSize, int *uncompressedSize)
{
unsigned char* RLDecompress(unsigned char* src, int srcSize, int* uncompressedSize) {
if (srcSize < 4)
goto fail;
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
unsigned char *dest = malloc(destSize);
unsigned char* dest = malloc(destSize);
if (dest == NULL)
goto fail;
@@ -20,16 +19,14 @@ unsigned char *RLDecompress(unsigned char *src, int srcSize, int *uncompressedSi
int srcPos = 4;
int destPos = 0;
for (;;)
{
for (;;) {
if (srcPos >= srcSize)
goto fail;
unsigned char flags = src[srcPos++];
bool compressed = ((flags & 0x80) != 0);
if (compressed)
{
if (compressed) {
int length = (flags & 0x7F) + 3;
unsigned char data = src[srcPos++];
@@ -38,9 +35,7 @@ unsigned char *RLDecompress(unsigned char *src, int srcSize, int *uncompressedSi
for (int i = 0; i < length; i++)
dest[destPos++] = data;
}
else
{
} else {
int length = (flags & 0x7F) + 1;
if (destPos + length > destSize)
@@ -50,8 +45,7 @@ unsigned char *RLDecompress(unsigned char *src, int srcSize, int *uncompressedSi
dest[destPos++] = src[srcPos++];
}
if (destPos == destSize)
{
if (destPos == destSize) {
*uncompressedSize = destSize;
return dest;
}
@@ -61,8 +55,7 @@ fail:
FATAL_ERROR("Fatal error while decompressing RL file.\n");
}
unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize)
{
unsigned char* RLCompress(unsigned char* src, int srcSize, int* compressedSize) {
if (srcSize <= 0)
goto fail;
@@ -71,7 +64,7 @@ unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize)
// Round up to the next multiple of four.
worstCaseDestSize = (worstCaseDestSize + 3) & ~3;
unsigned char *dest = malloc(worstCaseDestSize);
unsigned char* dest = malloc(worstCaseDestSize);
if (dest == NULL)
goto fail;
@@ -85,14 +78,12 @@ unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize)
int srcPos = 0;
int destPos = 4;
for (;;)
{
for (;;) {
bool compress = false;
int uncompressedStart = srcPos;
int uncompressedLength = 0;
while (srcPos < srcSize && uncompressedLength < (0x7F + 1))
{
while (srcPos < srcSize && uncompressedLength < (0x7F + 1)) {
compress = (srcPos + 2 < srcSize && src[srcPos] == src[srcPos + 1] && src[srcPos] == src[srcPos + 2]);
if (compress)
@@ -101,24 +92,20 @@ unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize)
srcPos++;
uncompressedLength++;
}
if (uncompressedLength > 0)
{
if (uncompressedLength > 0) {
dest[destPos++] = uncompressedLength - 1;
for (int i = 0; i < uncompressedLength; i++)
dest[destPos++] = src[uncompressedStart + i];
}
if (compress)
{
if (compress) {
unsigned char data = src[srcPos];
int compressedLength = 0;
while (compressedLength < (0x7F + 3)
&& srcPos + compressedLength < srcSize
&& src[srcPos + compressedLength] == data)
{
while (compressedLength < (0x7F + 3) && srcPos + compressedLength < srcSize &&
src[srcPos + compressedLength] == data) {
compressedLength++;
}
@@ -128,13 +115,11 @@ unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize)
srcPos += compressedLength;
}
if (srcPos == srcSize)
{
if (srcPos == srcSize) {
// Pad to multiple of 4 bytes.
int remainder = destPos % 4;
if (remainder != 0)
{
if (remainder != 0) {
for (int i = 0; i < 4 - remainder; i++)
dest[destPos++] = 0;
}
Executable → Regular
+2 -2
View File
@@ -3,7 +3,7 @@
#ifndef RL_H
#define RL_H
unsigned char *RLDecompress(unsigned char *src, int srcSize, int *uncompressedSize);
unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize);
unsigned char* RLDecompress(unsigned char* src, int srcSize, int* uncompressedSize);
unsigned char* RLCompress(unsigned char* src, int srcSize, int* compressedSize);
#endif // RL_H
Executable → Regular
+63 -68
View File
@@ -9,116 +9,111 @@
#include "global.h"
#include "util.h"
bool ParseNumber(char *s, char **end, int radix, int *intValue)
{
char *localEnd;
bool ParseNumber(char* s, char** end, int radix, int* intValue) {
char* localEnd;
if (end == NULL)
end = &localEnd;
if (end == NULL)
end = &localEnd;
errno = 0;
errno = 0;
const long longValue = strtol(s, end, radix);
const long longValue = strtol(s, end, radix);
if (*end == s)
return false; // not a number
if (*end == s)
return false; // not a number
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
return false;
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
return false;
if (longValue > INT_MAX)
return false;
if (longValue > INT_MAX)
return false;
if (longValue < INT_MIN)
return false;
if (longValue < INT_MIN)
return false;
*intValue = (int)longValue;
*intValue = (int)longValue;
return true;
return true;
}
char *GetFileExtension(char *path)
{
char *extension = path;
char* GetFileExtension(char* path) {
char* extension = path;
while (*extension != 0)
extension++;
while (*extension != 0)
extension++;
while (extension > path && *extension != '.')
extension--;
while (extension > path && *extension != '.')
extension--;
if (extension == path)
return NULL;
if (extension == path)
return NULL;
extension++;
extension++;
if (*extension == 0)
return NULL;
if (*extension == 0)
return NULL;
return extension;
return extension;
}
unsigned char *ReadWholeFile(char *path, int *size)
{
FILE *fp = fopen(path, "rb");
unsigned char* ReadWholeFile(char* path, int* size) {
FILE* fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
fseek(fp, 0, SEEK_END);
fseek(fp, 0, SEEK_END);
*size = ftell(fp);
*size = ftell(fp);
unsigned char *buffer = malloc(*size);
unsigned char* buffer = malloc(*size);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
rewind(fp);
rewind(fp);
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
fclose(fp);
fclose(fp);
return buffer;
return buffer;
}
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
{
FILE *fp = fopen(path, "rb");
unsigned char* ReadWholeFileZeroPadded(char* path, int* size, int padAmount) {
FILE* fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
fseek(fp, 0, SEEK_END);
fseek(fp, 0, SEEK_END);
*size = ftell(fp);
*size = ftell(fp);
unsigned char *buffer = calloc(*size + padAmount, 1);
unsigned char* buffer = calloc(*size + padAmount, 1);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
rewind(fp);
rewind(fp);
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
fclose(fp);
fclose(fp);
return buffer;
return buffer;
}
void WriteWholeFile(char *path, void *buffer, int bufferSize)
{
FILE *fp = fopen(path, "wb");
void WriteWholeFile(char* path, void* buffer, int bufferSize) {
FILE* fp = fopen(path, "wb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
if (fwrite(buffer, bufferSize, 1, fp) != 1)
FATAL_ERROR("Failed to write to \"%s\".\n", path);
if (fwrite(buffer, bufferSize, 1, fp) != 1)
FATAL_ERROR("Failed to write to \"%s\".\n", path);
fclose(fp);
fclose(fp);
}
Executable → Regular
+5 -5
View File
@@ -5,10 +5,10 @@
#include <stdbool.h>
bool ParseNumber(char *s, char **end, int radix, int *intValue);
char *GetFileExtension(char *path);
unsigned char *ReadWholeFile(char *path, int *size);
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount);
void WriteWholeFile(char *path, void *buffer, int bufferSize);
bool ParseNumber(char* s, char** end, int radix, int* intValue);
char* GetFileExtension(char* path);
unsigned char* ReadWholeFile(char* path, int* size);
unsigned char* ReadWholeFileZeroPadded(char* path, int* size, int padAmount);
void WriteWholeFile(char* path, void* buffer, int bufferSize);
#endif // UTIL_H
Executable → Regular
+233 -271
View File
@@ -42,8 +42,7 @@ static int s_memaccOp;
static int s_memaccParam1;
static int s_memaccParam2;
void PrintAgbHeader()
{
void PrintAgbHeader() {
std::fprintf(g_outputFile, "\t.include \"sound/MPlayDef.s\"\n\n");
std::fprintf(g_outputFile, "\t.equ\t%s_grp, voicegroup%03u\n", g_asmLabel.c_str(), g_voiceGroup);
std::fprintf(g_outputFile, "\t.equ\t%s_pri, %u\n", g_asmLabel.c_str(), g_priority);
@@ -65,8 +64,7 @@ void PrintAgbHeader()
std::fprintf(g_outputFile, "\t.align\t2\n");
}
void ResetTrackVars()
{
void ResetTrackVars() {
s_lastVelocity = -1;
s_lastNote = -1;
s_velocityChanged = false;
@@ -76,10 +74,8 @@ void ResetTrackVars()
s_inPattern = false;
}
void PrintWait(int wait)
{
if (wait > 0)
{
void PrintWait(int wait) {
if (wait > 0) {
std::fprintf(g_outputFile, "\t.byte\tW%02d\n", wait);
s_velocityChanged = true;
s_noteChanged = true;
@@ -87,27 +83,20 @@ void PrintWait(int wait)
}
}
void PrintOp(int wait, std::string name, const char *format, ...)
{
void PrintOp(int wait, std::string name, const char* format, ...) {
std::va_list args;
va_start(args, format);
std::fprintf(g_outputFile, "\t.byte\t\t");
if (format != nullptr)
{
if (!g_compressionEnabled || s_lastOpName != name)
{
if (format != nullptr) {
if (!g_compressionEnabled || s_lastOpName != name) {
std::fprintf(g_outputFile, "%s, ", name.c_str());
s_lastOpName = name;
}
else
{
} else {
std::fprintf(g_outputFile, " ");
}
std::vfprintf(g_outputFile, format, args);
}
else
{
} else {
std::fputs(name.c_str(), g_outputFile);
s_lastOpName = name;
}
@@ -119,8 +108,7 @@ void PrintOp(int wait, std::string name, const char *format, ...)
PrintWait(wait);
}
void PrintByte(const char *format, ...)
{
void PrintByte(const char* format, ...) {
std::va_list args;
va_start(args, format);
std::fprintf(g_outputFile, "\t.byte\t");
@@ -132,8 +120,7 @@ void PrintByte(const char *format, ...)
va_end(args);
}
void PrintWord(const char *format, ...)
{
void PrintWord(const char* format, ...) {
std::va_list args;
va_start(args, format);
std::fprintf(g_outputFile, "\t .word\t");
@@ -142,8 +129,7 @@ void PrintWord(const char *format, ...)
va_end(args);
}
void PrintNote(const Event& event)
{
void PrintNote(const Event& event) {
int note = event.note;
int velocity = g_noteVelocityLUT[event.param1];
int duration = -1;
@@ -173,8 +159,7 @@ void PrintNote(const Event& event)
bool noteChanged = true;
bool velocityChanged = true;
if (g_compressionEnabled)
{
if (g_compressionEnabled) {
noteChanged = (note != s_lastNote);
velocityChanged = (velocity != s_lastVelocity);
}
@@ -184,8 +169,7 @@ void PrintNote(const Event& event)
else
s_lastOpName = "";
if (noteChanged || velocityChanged || (gateTimeParam > 0))
{
if (noteChanged || velocityChanged || (gateTimeParam > 0)) {
s_lastNote = note;
char noteBuf[16];
@@ -197,20 +181,15 @@ void PrintNote(const Event& event)
char velocityBuf[16];
if (velocityChanged || (gateTimeParam > 0))
{
if (velocityChanged || (gateTimeParam > 0)) {
s_lastVelocity = velocity;
std::snprintf(velocityBuf, sizeof(velocityBuf), ", v%03u", velocity);
}
else
{
} else {
velocityBuf[0] = 0;
}
PrintOp(event.time, opName, "%s%s%s", noteBuf, velocityBuf, gtpBuf);
}
else
{
} else {
PrintOp(event.time, opName, 0);
}
@@ -218,20 +197,16 @@ void PrintNote(const Event& event)
s_velocityChanged = velocityChanged;
}
void PrintEndOfTieOp(const Event& event)
{
void PrintEndOfTieOp(const Event& event) {
int note = event.note;
bool noteChanged = (note != s_lastNote);
if (!noteChanged || !s_noteChanged)
s_lastOpName = "";
if (!noteChanged && g_compressionEnabled)
{
if (!noteChanged && g_compressionEnabled) {
PrintOp(event.time, "EOT ", nullptr);
}
else
{
} else {
s_lastNote = note;
if (note >= 24)
PrintOp(event.time, "EOT ", g_noteTable[note % 12], note / 12 - 2);
@@ -242,181 +217,174 @@ void PrintEndOfTieOp(const Event& event)
s_noteChanged = noteChanged;
}
void PrintSeqLoopLabel(const Event& event)
{
void PrintSeqLoopLabel(const Event& event) {
s_blockNum = event.param1 + 1;
std::fprintf(g_outputFile, "%s_%u_B%u::\n", g_asmLabel.c_str(), g_agbTrack, s_blockNum);
PrintWait(event.time);
ResetTrackVars();
}
void PrintMemAcc(const Event& event)
{
switch (s_memaccOp)
{
case 0x00:
PrintByte("MEMACC, mem_set, 0x%02X, %u", s_memaccParam1, event.param2);
break;
case 0x01:
PrintByte("MEMACC, mem_add, 0x%02X, %u", s_memaccParam1, event.param2);
break;
case 0x02:
PrintByte("MEMACC, mem_sub, 0x%02X, %u", s_memaccParam1, event.param2);
break;
case 0x03:
PrintByte("MEMACC, mem_mem_set, 0x%02X, 0x%02X", s_memaccParam1, event.param2);
break;
case 0x04:
PrintByte("MEMACC, mem_mem_add, 0x%02X, 0x%02X", s_memaccParam1, event.param2);
break;
case 0x05:
PrintByte("MEMACC, mem_mem_sub, 0x%02X, 0x%02X", s_memaccParam1, event.param2);
break;
// TODO: everything else
case 0x06:
break;
case 0x07:
break;
case 0x08:
break;
case 0x09:
break;
case 0x0A:
break;
case 0x0B:
break;
case 0x0C:
break;
case 0x0D:
break;
case 0x0E:
break;
case 0x0F:
break;
case 0x10:
break;
case 0x11:
break;
case 0x46:
break;
case 0x47:
break;
case 0x48:
break;
case 0x49:
break;
case 0x4A:
break;
case 0x4B:
break;
case 0x4C:
break;
case 0x4D:
break;
case 0x4E:
break;
case 0x4F:
break;
case 0x50:
break;
case 0x51:
break;
default:
break;
void PrintMemAcc(const Event& event) {
switch (s_memaccOp) {
case 0x00:
PrintByte("MEMACC, mem_set, 0x%02X, %u", s_memaccParam1, event.param2);
break;
case 0x01:
PrintByte("MEMACC, mem_add, 0x%02X, %u", s_memaccParam1, event.param2);
break;
case 0x02:
PrintByte("MEMACC, mem_sub, 0x%02X, %u", s_memaccParam1, event.param2);
break;
case 0x03:
PrintByte("MEMACC, mem_mem_set, 0x%02X, 0x%02X", s_memaccParam1, event.param2);
break;
case 0x04:
PrintByte("MEMACC, mem_mem_add, 0x%02X, 0x%02X", s_memaccParam1, event.param2);
break;
case 0x05:
PrintByte("MEMACC, mem_mem_sub, 0x%02X, 0x%02X", s_memaccParam1, event.param2);
break;
// TODO: everything else
case 0x06:
break;
case 0x07:
break;
case 0x08:
break;
case 0x09:
break;
case 0x0A:
break;
case 0x0B:
break;
case 0x0C:
break;
case 0x0D:
break;
case 0x0E:
break;
case 0x0F:
break;
case 0x10:
break;
case 0x11:
break;
case 0x46:
break;
case 0x47:
break;
case 0x48:
break;
case 0x49:
break;
case 0x4A:
break;
case 0x4B:
break;
case 0x4C:
break;
case 0x4D:
break;
case 0x4E:
break;
case 0x4F:
break;
case 0x50:
break;
case 0x51:
break;
default:
break;
}
PrintWait(event.time);
}
void PrintExtendedOp(const Event& event)
{
void PrintExtendedOp(const Event& event) {
// TODO: support for other extended commands
switch (s_extendedCommand)
{
case 0x08:
PrintOp(event.time, "XCMD ", "xIECV , %u", event.param2);
break;
case 0x09:
PrintOp(event.time, "XCMD ", "xIECL , %u", event.param2);
break;
default:
PrintWait(event.time);
break;
switch (s_extendedCommand) {
case 0x08:
PrintOp(event.time, "XCMD ", "xIECV , %u", event.param2);
break;
case 0x09:
PrintOp(event.time, "XCMD ", "xIECL , %u", event.param2);
break;
default:
PrintWait(event.time);
break;
}
}
void PrintControllerOp(const Event& event)
{
switch (event.param1)
{
case 0x01:
PrintOp(event.time, "MOD ", "%u", event.param2);
break;
case 0x07:
PrintOp(event.time, "VOL ", "%u*%s_mvl/mxv", event.param2, g_asmLabel.c_str());
break;
case 0x0A:
PrintOp(event.time, "PAN ", "c_v%+d", event.param2 - 64);
break;
case 0x0C:
case 0x10:
PrintMemAcc(event);
break;
case 0x0D:
s_memaccOp = event.param2;
PrintWait(event.time);
break;
case 0x0E:
s_memaccParam1 = event.param2;
PrintWait(event.time);
break;
case 0x0F:
s_memaccParam2 = event.param2;
PrintWait(event.time);
break;
case 0x11:
std::fprintf(g_outputFile, "%s_%u_L%u::\n", g_asmLabel.c_str(), g_agbTrack, event.param2);
PrintWait(event.time);
ResetTrackVars();
break;
case 0x14:
PrintOp(event.time, "BENDR ", "%u", event.param2);
break;
case 0x15:
PrintOp(event.time, "LFOS ", "%u", event.param2);
break;
case 0x16:
PrintOp(event.time, "MODT ", "%u", event.param2);
break;
case 0x18:
PrintOp(event.time, "TUNE ", "c_v%+d", event.param2 - 64);
break;
case 0x1A:
PrintOp(event.time, "LFODL ", "%u", event.param2);
break;
case 0x1D:
case 0x1F:
PrintExtendedOp(event);
break;
case 0x1E:
s_extendedCommand = event.param2;
// TODO: loop op
break;
case 0x21:
case 0x27:
PrintByte("PRIO , %u", event.param2);
PrintWait(event.time);
break;
default:
PrintWait(event.time);
break;
void PrintControllerOp(const Event& event) {
switch (event.param1) {
case 0x01:
PrintOp(event.time, "MOD ", "%u", event.param2);
break;
case 0x07:
PrintOp(event.time, "VOL ", "%u*%s_mvl/mxv", event.param2, g_asmLabel.c_str());
break;
case 0x0A:
PrintOp(event.time, "PAN ", "c_v%+d", event.param2 - 64);
break;
case 0x0C:
case 0x10:
PrintMemAcc(event);
break;
case 0x0D:
s_memaccOp = event.param2;
PrintWait(event.time);
break;
case 0x0E:
s_memaccParam1 = event.param2;
PrintWait(event.time);
break;
case 0x0F:
s_memaccParam2 = event.param2;
PrintWait(event.time);
break;
case 0x11:
std::fprintf(g_outputFile, "%s_%u_L%u::\n", g_asmLabel.c_str(), g_agbTrack, event.param2);
PrintWait(event.time);
ResetTrackVars();
break;
case 0x14:
PrintOp(event.time, "BENDR ", "%u", event.param2);
break;
case 0x15:
PrintOp(event.time, "LFOS ", "%u", event.param2);
break;
case 0x16:
PrintOp(event.time, "MODT ", "%u", event.param2);
break;
case 0x18:
PrintOp(event.time, "TUNE ", "c_v%+d", event.param2 - 64);
break;
case 0x1A:
PrintOp(event.time, "LFODL ", "%u", event.param2);
break;
case 0x1D:
case 0x1F:
PrintExtendedOp(event);
break;
case 0x1E:
s_extendedCommand = event.param2;
// TODO: loop op
break;
case 0x21:
case 0x27:
PrintByte("PRIO , %u", event.param2);
PrintWait(event.time);
break;
default:
PrintWait(event.time);
break;
}
}
void PrintAgbTrack(std::vector<Event>& events)
{
std::fprintf(g_outputFile, "\n@**************** Track %u (Midi-Chn.%u) ****************@\n\n", g_agbTrack, g_midiChan + 1);
void PrintAgbTrack(std::vector<Event>& events) {
std::fprintf(g_outputFile, "\n@**************** Track %u (Midi-Chn.%u) ****************@\n\n", g_agbTrack,
g_midiChan + 1);
std::fprintf(g_outputFile, "%s_%u::\n", g_asmLabel.c_str(), g_agbTrack);
int wholeNoteCount = 0;
@@ -426,13 +394,11 @@ void PrintAgbTrack(std::vector<Event>& events)
bool foundVolBeforeNote = false;
for (const Event& event : events)
{
for (const Event& event : events) {
if (event.type == EventType::Note)
break;
if (event.type == EventType::Controller && event.param1 == 0x07)
{
if (event.type == EventType::Controller && event.param1 == 0x07) {
foundVolBeforeNote = true;
break;
}
@@ -444,12 +410,10 @@ void PrintAgbTrack(std::vector<Event>& events)
PrintWait(g_initialWait);
PrintByte("KEYSH , %s_key%+d", g_asmLabel.c_str(), 0);
for (unsigned i = 0; events[i].type != EventType::EndOfTrack; i++)
{
for (unsigned i = 0; events[i].type != EventType::EndOfTrack; i++) {
const Event& event = events[i];
if (IsPatternBoundary(event.type))
{
if (IsPatternBoundary(event.type)) {
if (s_inPattern)
PrintByte("PEND");
s_inPattern = false;
@@ -458,75 +422,73 @@ void PrintAgbTrack(std::vector<Event>& events)
if (event.type == EventType::WholeNoteMark || event.type == EventType::Pattern)
std::fprintf(g_outputFile, "@ %03d ----------------------------------------\n", wholeNoteCount++);
switch (event.type)
{
case EventType::Note:
PrintNote(event);
break;
case EventType::EndOfTie:
PrintEndOfTieOp(event);
break;
case EventType::Label:
PrintSeqLoopLabel(event);
break;
case EventType::LoopEnd:
PrintByte("GOTO");
PrintWord("%s_%u_B%u", g_asmLabel.c_str(), g_agbTrack, loopEndBlockNum);
//PrintSeqLoopLabel(event); // Breaks same note in EOT bgmCrenelStorm 0xDD4356
PrintWait(event.time); // instead just print the wait
break;
case EventType::LoopEndBegin:
PrintByte("GOTO");
PrintWord("%s_%u_B%u", g_asmLabel.c_str(), g_agbTrack, loopEndBlockNum);
PrintSeqLoopLabel(event);
loopEndBlockNum = s_blockNum;
break;
case EventType::LoopBegin:
PrintSeqLoopLabel(event);
loopEndBlockNum = s_blockNum;
break;
case EventType::WholeNoteMark:
if (event.param2 & 0x80000000)
{
std::fprintf(g_outputFile, "%s_%u_%03lu::\n", g_asmLabel.c_str(), g_agbTrack, (unsigned long)(event.param2 & 0x7FFFFFFF));
switch (event.type) {
case EventType::Note:
PrintNote(event);
break;
case EventType::EndOfTie:
PrintEndOfTieOp(event);
break;
case EventType::Label:
PrintSeqLoopLabel(event);
break;
case EventType::LoopEnd:
PrintByte("GOTO");
PrintWord("%s_%u_B%u", g_asmLabel.c_str(), g_agbTrack, loopEndBlockNum);
// PrintSeqLoopLabel(event); // Breaks same note in EOT bgmCrenelStorm 0xDD4356
PrintWait(event.time); // instead just print the wait
break;
case EventType::LoopEndBegin:
PrintByte("GOTO");
PrintWord("%s_%u_B%u", g_asmLabel.c_str(), g_agbTrack, loopEndBlockNum);
PrintSeqLoopLabel(event);
loopEndBlockNum = s_blockNum;
break;
case EventType::LoopBegin:
PrintSeqLoopLabel(event);
loopEndBlockNum = s_blockNum;
break;
case EventType::WholeNoteMark:
if (event.param2 & 0x80000000) {
std::fprintf(g_outputFile, "%s_%u_%03lu::\n", g_asmLabel.c_str(), g_agbTrack,
(unsigned long)(event.param2 & 0x7FFFFFFF));
ResetTrackVars();
s_inPattern = true;
}
PrintWait(event.time);
break;
case EventType::Pattern:
PrintByte("PATT");
PrintWord("%s_%u_%03lu", g_asmLabel.c_str(), g_agbTrack, event.param2);
while (!IsPatternBoundary(events[i + 1].type))
i++;
ResetTrackVars();
s_inPattern = true;
}
PrintWait(event.time);
break;
case EventType::Pattern:
PrintByte("PATT");
PrintWord("%s_%u_%03lu", g_asmLabel.c_str(), g_agbTrack, event.param2);
while (!IsPatternBoundary(events[i + 1].type))
i++;
ResetTrackVars();
break;
case EventType::Tempo:
PrintByte("TEMPO , %u*%s_tbs/2", 60000000 / event.param2, g_asmLabel.c_str());
PrintWait(event.time);
break;
case EventType::InstrumentChange:
PrintOp(event.time, "VOICE ", "%u", event.param1);
break;
case EventType::PitchBend:
PrintOp(event.time, "BEND ", "c_v%+d", event.param2 - 64);
break;
case EventType::Controller:
PrintControllerOp(event);
break;
default:
PrintWait(event.time);
break;
break;
case EventType::Tempo:
PrintByte("TEMPO , %u*%s_tbs/2", 60000000 / event.param2, g_asmLabel.c_str());
PrintWait(event.time);
break;
case EventType::InstrumentChange:
PrintOp(event.time, "VOICE ", "%u", event.param1);
break;
case EventType::PitchBend:
PrintOp(event.time, "BEND ", "c_v%+d", event.param2 - 64);
break;
case EventType::Controller:
PrintControllerOp(event);
break;
default:
PrintWait(event.time);
break;
}
}
PrintByte("FINE");
}
void PrintAgbFooter()
{
void PrintAgbFooter() {
int trackCount = g_agbTrack - 1;
std::fprintf(g_outputFile, "\n@******************************************************@\n");
Executable → Regular
+1 -2
View File
@@ -23,8 +23,7 @@
#include <cstdarg>
// Reports an error diagnostic and terminates the program.
[[noreturn]] void RaiseError(const char* format, ...)
{
[[noreturn]] void RaiseError(const char* format, ...) {
const int bufferSize = 1024;
char buffer[bufferSize];
std::va_list args;
Executable → Regular
+70 -88
View File
@@ -42,52 +42,44 @@ int g_clocksPerBeat = 1;
bool g_exactGateTime = false;
bool g_compressionEnabled = true;
[[noreturn]] static void PrintUsage()
{
std::printf(
"Usage: MID2AGB name [options]\n"
"\n"
" input_file filename(.mid) of MIDI file\n"
" output_file filename(.s) for AGB file (default:input_file)\n"
"\n"
"options -L??? label for assembler (default:output_file)\n"
" -V??? master volume (default:127)\n"
" -G??? voice group number (default:0)\n"
" -P??? priority (default:0)\n"
" -R??? reverb (default:off)\n"
" -X 48 clocks/beat (default:24 clocks/beat)\n"
" -E exact gate-time\n"
" -N no compression\n"
);
[[noreturn]] static void PrintUsage() {
std::printf("Usage: MID2AGB name [options]\n"
"\n"
" input_file filename(.mid) of MIDI file\n"
" output_file filename(.s) for AGB file (default:input_file)\n"
"\n"
"options -L??? label for assembler (default:output_file)\n"
" -V??? master volume (default:127)\n"
" -G??? voice group number (default:0)\n"
" -P??? priority (default:0)\n"
" -R??? reverb (default:off)\n"
" -X 48 clocks/beat (default:24 clocks/beat)\n"
" -E exact gate-time\n"
" -N no compression\n");
std::exit(1);
}
static std::string StripExtension(std::string s)
{
static std::string StripExtension(std::string s) {
std::size_t pos = s.find_last_of('.');
if (pos > 0 && pos != std::string::npos)
{
if (pos > 0 && pos != std::string::npos) {
s = s.substr(0, pos);
}
return s;
}
static std::string GetExtension(std::string s)
{
static std::string GetExtension(std::string s) {
std::size_t pos = s.find_last_of('.');
if (pos > 0 && pos != std::string::npos)
{
if (pos > 0 && pos != std::string::npos) {
return s.substr(pos + 1);
}
return "";
}
static std::string BaseName(std::string s)
{
static std::string BaseName(std::string s) {
std::size_t posAfterSlash = s.find_last_of("/\\");
if (posAfterSlash == std::string::npos)
@@ -102,11 +94,10 @@ static std::string BaseName(std::string s)
return s;
}
static const char *GetArgument(int argc, char **argv, int& index)
{
static const char* GetArgument(int argc, char** argv, int& index) {
assert(index >= 0 && index < argc);
const char *option = argv[index];
const char* option = argv[index];
assert(option != nullptr);
assert(option[0] == '-');
@@ -116,77 +107,68 @@ static const char *GetArgument(int argc, char **argv, int& index)
return option + 2;
// Otherwise, try to get the next arg.
if (index + 1 < argc)
{
if (index + 1 < argc) {
index++;
return argv[index];
}
else
{
} else {
return nullptr;
}
}
int main(int argc, char** argv)
{
int main(int argc, char** argv) {
std::string inputFilename;
std::string outputFilename;
for (int i = 1; i < argc; i++)
{
const char *option = argv[i];
for (int i = 1; i < argc; i++) {
const char* option = argv[i];
if (option[0] == '-' && option[1] != '\0')
{
const char *arg;
if (option[0] == '-' && option[1] != '\0') {
const char* arg;
switch (std::toupper(option[1]))
{
case 'E':
g_exactGateTime = true;
break;
case 'G':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
switch (std::toupper(option[1])) {
case 'E':
g_exactGateTime = true;
break;
case 'G':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_voiceGroup = std::stoi(arg);
break;
case 'L':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_asmLabel = arg;
break;
case 'N':
g_compressionEnabled = false;
break;
case 'P':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_priority = std::stoi(arg);
break;
case 'R':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_reverb = std::stoi(arg);
break;
case 'V':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_masterVolume = std::stoi(arg);
break;
case 'X':
g_clocksPerBeat = 2;
break;
default:
PrintUsage();
g_voiceGroup = std::stoi(arg);
break;
case 'L':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_asmLabel = arg;
break;
case 'N':
g_compressionEnabled = false;
break;
case 'P':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_priority = std::stoi(arg);
break;
case 'R':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_reverb = std::stoi(arg);
break;
case 'V':
arg = GetArgument(argc, argv, i);
if (arg == nullptr)
PrintUsage();
g_masterVolume = std::stoi(arg);
break;
case 'X':
g_clocksPerBeat = 2;
break;
default:
PrintUsage();
}
}
else
{
} else {
if (inputFilename.empty())
inputFilename = argv[i];
else if (outputFilename.empty())
Executable → Regular
+204 -320
View File
@@ -30,8 +30,7 @@
#include "agb.h"
#include "tables.h"
enum class MidiEventCategory
{
enum class MidiEventCategory {
Control,
SysEx,
Meta,
@@ -54,20 +53,17 @@ static int s_minNote;
static int s_maxNote;
static int s_runningStatus;
void Seek(long offset)
{
void Seek(long offset) {
if (std::fseek(g_inputFile, offset, SEEK_SET) != 0)
RaiseError("failed to seek to %l", offset);
}
void Skip(long offset)
{
void Skip(long offset) {
if (std::fseek(g_inputFile, offset, SEEK_CUR) != 0)
RaiseError("failed to skip %l bytes", offset);
}
std::string ReadSignature()
{
std::string ReadSignature() {
char signature[4];
if (std::fread(signature, 4, 1, g_inputFile) != 1)
@@ -76,8 +72,7 @@ std::string ReadSignature()
return std::string(signature, 4);
}
std::uint32_t ReadInt8()
{
std::uint32_t ReadInt8() {
int c = std::fgetc(g_inputFile);
if (c < 0)
@@ -86,16 +81,14 @@ std::uint32_t ReadInt8()
return c;
}
std::uint32_t ReadInt16()
{
std::uint32_t ReadInt16() {
std::uint32_t val = 0;
val |= ReadInt8() << 8;
val |= ReadInt8();
return val;
}
std::uint32_t ReadInt24()
{
std::uint32_t ReadInt24() {
std::uint32_t val = 0;
val |= ReadInt8() << 16;
val |= ReadInt8() << 8;
@@ -103,8 +96,7 @@ std::uint32_t ReadInt24()
return val;
}
std::uint32_t ReadInt32()
{
std::uint32_t ReadInt32() {
std::uint32_t val = 0;
val |= ReadInt8() << 24;
val |= ReadInt8() << 16;
@@ -113,13 +105,11 @@ std::uint32_t ReadInt32()
return val;
}
std::uint32_t ReadVLQ()
{
std::uint32_t ReadVLQ() {
std::uint32_t val = 0;
std::uint32_t c;
do
{
do {
c = ReadInt8();
val <<= 7;
val |= (c & 0x7F);
@@ -128,8 +118,7 @@ std::uint32_t ReadVLQ()
return val;
}
void ReadMidiFileHeader()
{
void ReadMidiFileHeader() {
Seek(0);
if (ReadSignature() != "MThd")
@@ -153,8 +142,7 @@ void ReadMidiFileHeader()
RaiseError("unsupported MIDI time division (%d)", g_midiTimeDiv);
}
long ReadMidiTrackHeader(long offset)
{
long ReadMidiTrackHeader(long offset) {
Seek(offset);
if (ReadSignature() != "MTrk")
@@ -167,82 +155,65 @@ long ReadMidiTrackHeader(long offset)
return size + 8;
}
void StartTrack()
{
void StartTrack() {
Seek(s_trackDataStart);
s_absoluteTime = 0;
s_runningStatus = 0;
}
void SkipEventData()
{
void SkipEventData() {
Skip(ReadVLQ());
}
void DetermineEventCategory(MidiEventCategory& category, int& typeChan, int& size)
{
void DetermineEventCategory(MidiEventCategory& category, int& typeChan, int& size) {
typeChan = ReadInt8();
if (typeChan < 0x80)
{
if (typeChan < 0x80) {
// If data byte was found, use the running status.
ungetc(typeChan, g_inputFile);
typeChan = s_runningStatus;
}
if (typeChan == 0xFF)
{
if (typeChan == 0xFF) {
category = MidiEventCategory::Meta;
size = 0;
s_runningStatus = 0;
}
else if (typeChan >= 0xF0)
{
} else if (typeChan >= 0xF0) {
category = MidiEventCategory::SysEx;
size = 0;
s_runningStatus = 0;
}
else if (typeChan >= 0x80)
{
} else if (typeChan >= 0x80) {
category = MidiEventCategory::Control;
switch (typeChan >> 4)
{
case 0xC:
case 0xD:
size = 1;
break;
default:
size = 2;
break;
switch (typeChan >> 4) {
case 0xC:
case 0xD:
size = 1;
break;
default:
size = 2;
break;
}
s_runningStatus = typeChan;
}
else
{
} else {
category = MidiEventCategory::Invalid;
}
}
void MakeBlockEvent(Event& event, EventType type)
{
void MakeBlockEvent(Event& event, EventType type) {
event.type = type;
event.param1 = s_blockCount++;
event.param2 = 0;
}
std::string ReadEventText()
{
std::string ReadEventText() {
char buffer[2];
std::uint32_t length = ReadVLQ();
if (length <= 2)
{
if (length <= 2) {
if (fread(buffer, length, 1, g_inputFile) != 1)
RaiseError("failed to read event text");
}
else
{
} else {
Skip(length);
length = 0;
}
@@ -250,8 +221,7 @@ std::string ReadEventText()
return std::string(buffer, length);
}
bool ReadSeqEvent(Event& event)
{
bool ReadSeqEvent(Event& event) {
s_absoluteTime += ReadVLQ();
event.time = s_absoluteTime;
@@ -261,14 +231,12 @@ bool ReadSeqEvent(Event& event)
DetermineEventCategory(category, typeChan, size);
if (category == MidiEventCategory::Control)
{
if (category == MidiEventCategory::Control) {
Skip(size);
return false;
}
if (category == MidiEventCategory::SysEx)
{
if (category == MidiEventCategory::SysEx) {
SkipEventData();
return false;
}
@@ -279,8 +247,7 @@ bool ReadSeqEvent(Event& event)
// meta event
int metaEventType = ReadInt8();
if (metaEventType >= 1 && metaEventType <= 7)
{
if (metaEventType >= 1 && metaEventType <= 7) {
// text event
std::string text = ReadEventText();
@@ -294,69 +261,63 @@ bool ReadSeqEvent(Event& event)
MakeBlockEvent(event, EventType::Label);
else
return false;
}
else
{
switch (metaEventType)
{
case 0x2F: // end of track
SkipEventData();
event.type = EventType::EndOfTrack;
event.param1 = 0;
event.param2 = 0;
break;
case 0x51: // tempo
if (ReadVLQ() != 3)
RaiseError("invalid tempo size");
} else {
switch (metaEventType) {
case 0x2F: // end of track
SkipEventData();
event.type = EventType::EndOfTrack;
event.param1 = 0;
event.param2 = 0;
break;
case 0x51: // tempo
if (ReadVLQ() != 3)
RaiseError("invalid tempo size");
event.type = EventType::Tempo;
event.param1 = 0;
event.param2 = ReadInt24();
break;
case 0x58: // time signature
{
if (ReadVLQ() != 4)
RaiseError("invalid time signature size");
event.type = EventType::Tempo;
event.param1 = 0;
event.param2 = ReadInt24();
break;
case 0x58: // time signature
{
if (ReadVLQ() != 4)
RaiseError("invalid time signature size");
int numerator = ReadInt8();
int denominatorExponent = ReadInt8();
int numerator = ReadInt8();
int denominatorExponent = ReadInt8();
if (denominatorExponent >= 16)
RaiseError("invalid time signature denominator");
if (denominatorExponent >= 16)
RaiseError("invalid time signature denominator");
Skip(2); // ignore other values
Skip(2); // ignore other values
int clockTicks = 96 * numerator * g_clocksPerBeat;
int denominator = 1 << denominatorExponent;
int timeSig = clockTicks / denominator;
int clockTicks = 96 * numerator * g_clocksPerBeat;
int denominator = 1 << denominatorExponent;
int timeSig = clockTicks / denominator;
if (timeSig <= 0 || timeSig >= 0x10000)
RaiseError("invalid time signature");
if (timeSig <= 0 || timeSig >= 0x10000)
RaiseError("invalid time signature");
event.type = EventType::TimeSignature;
event.param1 = 0;
event.param2 = timeSig;
break;
}
default:
SkipEventData();
return false;
event.type = EventType::TimeSignature;
event.param1 = 0;
event.param2 = timeSig;
break;
}
default:
SkipEventData();
return false;
}
}
return true;
}
void ReadSeqEvents()
{
void ReadSeqEvents() {
StartTrack();
for (;;)
{
for (;;) {
Event event = {};
if (ReadSeqEvent(event))
{
if (ReadSeqEvent(event)) {
s_seqEvents.push_back(event);
if (event.type == EventType::EndOfTrack)
@@ -365,8 +326,7 @@ void ReadSeqEvents()
}
}
bool CheckNoteEnd(Event& event)
{
bool CheckNoteEnd(Event& event) {
event.param2 += ReadVLQ();
MidiEventCategory category;
@@ -375,50 +335,45 @@ bool CheckNoteEnd(Event& event)
DetermineEventCategory(category, typeChan, size);
if (category == MidiEventCategory::Control)
{
if (category == MidiEventCategory::Control) {
int chan = typeChan & 0xF;
if (chan != g_midiChan)
{
if (chan != g_midiChan) {
Skip(size);
return false;
}
switch (typeChan & 0xF0)
{
case 0x80: // note off
{
int note = ReadInt8();
ReadInt8(); // ignore velocity
if (note == event.note)
return true;
break;
}
case 0x90: // note on
{
int note = ReadInt8();
int velocity = ReadInt8();
if (velocity == 0 && note == event.note)
return true;
break;
}
default:
Skip(size);
break;
switch (typeChan & 0xF0) {
case 0x80: // note off
{
int note = ReadInt8();
ReadInt8(); // ignore velocity
if (note == event.note)
return true;
break;
}
case 0x90: // note on
{
int note = ReadInt8();
int velocity = ReadInt8();
if (velocity == 0 && note == event.note)
return true;
break;
}
default:
Skip(size);
break;
}
return false;
}
if (category == MidiEventCategory::SysEx)
{
if (category == MidiEventCategory::SysEx) {
SkipEventData();
return false;
}
if (category == MidiEventCategory::Meta)
{
if (category == MidiEventCategory::Meta) {
int metaEventType = ReadInt8();
SkipEventData();
@@ -431,8 +386,7 @@ bool CheckNoteEnd(Event& event)
RaiseError("invalid event");
}
void FindNoteEnd(Event& event)
{
void FindNoteEnd(Event& event) {
// Save the current file position and running status
// which get modified by CheckNoteEnd.
long startPos = ftell(g_inputFile);
@@ -447,8 +401,7 @@ void FindNoteEnd(Event& event)
s_runningStatus = savedRunningStatus;
}
bool ReadTrackEvent(Event& event)
{
bool ReadTrackEvent(Event& event) {
s_absoluteTime += ReadVLQ();
event.time = s_absoluteTime;
@@ -458,74 +411,66 @@ bool ReadTrackEvent(Event& event)
DetermineEventCategory(category, typeChan, size);
if (category == MidiEventCategory::Control)
{
if (category == MidiEventCategory::Control) {
int chan = typeChan & 0xF;
if (chan != g_midiChan)
{
if (chan != g_midiChan) {
Skip(size);
return false;
}
switch (typeChan & 0xF0)
{
case 0x90: // note on
{
int note = ReadInt8();
int velocity = ReadInt8();
if (velocity != 0)
switch (typeChan & 0xF0) {
case 0x90: // note on
{
event.type = EventType::Note;
event.note = note;
event.param1 = velocity;
FindNoteEnd(event);
if (event.param2 > 0)
{
if (note < s_minNote)
s_minNote = note;
if (note > s_maxNote)
s_maxNote = note;
int note = ReadInt8();
int velocity = ReadInt8();
if (velocity != 0) {
event.type = EventType::Note;
event.note = note;
event.param1 = velocity;
FindNoteEnd(event);
if (event.param2 > 0) {
if (note < s_minNote)
s_minNote = note;
if (note > s_maxNote)
s_maxNote = note;
}
}
break;
}
break;
}
case 0xB0: // controller event
event.type = EventType::Controller;
event.param1 = ReadInt8(); // controller index
event.param2 = ReadInt8(); // value
break;
case 0xC0: // instrument change
event.type = EventType::InstrumentChange;
event.param1 = ReadInt8(); // instrument
event.param2 = 0;
break;
case 0xE0: // pitch bend
event.type = EventType::PitchBend;
event.param1 = ReadInt8();
event.param2 = ReadInt8();
break;
default:
Skip(size);
return false;
case 0xB0: // controller event
event.type = EventType::Controller;
event.param1 = ReadInt8(); // controller index
event.param2 = ReadInt8(); // value
break;
case 0xC0: // instrument change
event.type = EventType::InstrumentChange;
event.param1 = ReadInt8(); // instrument
event.param2 = 0;
break;
case 0xE0: // pitch bend
event.type = EventType::PitchBend;
event.param1 = ReadInt8();
event.param2 = ReadInt8();
break;
default:
Skip(size);
return false;
}
return true;
}
if (category == MidiEventCategory::SysEx)
{
if (category == MidiEventCategory::SysEx) {
SkipEventData();
return false;
}
if (category == MidiEventCategory::Meta)
{
if (category == MidiEventCategory::Meta) {
int metaEventType = ReadInt8();
if (metaEventType >= 1 && metaEventType <= 7)
{
if (metaEventType >= 1 && metaEventType <= 7) {
// text event
std::string text = ReadEventText();
@@ -540,17 +485,13 @@ bool ReadTrackEvent(Event& event)
else
return false;
return true;
}
else if (metaEventType == 0x2F)
{
} else if (metaEventType == 0x2F) {
SkipEventData();
event.type = EventType::EndOfTrack;
event.param1 = 0;
event.param2 = 0;
return true;
}
else
{
} else {
SkipEventData();
}
@@ -560,8 +501,7 @@ bool ReadTrackEvent(Event& event)
RaiseError("invalid event");
}
void ReadTrackEvents()
{
void ReadTrackEvents() {
StartTrack();
s_trackEvents.clear();
@@ -569,12 +509,10 @@ void ReadTrackEvents()
s_minNote = 0xFF;
s_maxNote = 0;
for (;;)
{
for (;;) {
Event event = {};
if (ReadTrackEvent(event))
{
if (ReadTrackEvent(event)) {
s_trackEvents.push_back(event);
if (event.type == EventType::EndOfTrack)
@@ -583,8 +521,7 @@ void ReadTrackEvents()
}
}
bool EventCompare(const Event& event1, const Event& event2)
{
bool EventCompare(const Event& event1, const Event& event2) {
if (event1.time < event2.time)
return true;
@@ -606,8 +543,7 @@ bool EventCompare(const Event& event1, const Event& event2)
if (event1Type > event2Type)
return false;
if (event1.type == EventType::EndOfTie)
{
if (event1.type == EventType::EndOfTie) {
if (event1.note < event2.note)
return true;
@@ -618,16 +554,14 @@ bool EventCompare(const Event& event1, const Event& event2)
return false;
}
std::unique_ptr<std::vector<Event>> MergeEvents()
{
std::unique_ptr<std::vector<Event>> MergeEvents() {
std::unique_ptr<std::vector<Event>> events(new std::vector<Event>());
unsigned trackEventPos = 0;
unsigned seqEventPos = 0;
while (s_trackEvents[trackEventPos].type != EventType::EndOfTrack
&& s_seqEvents[seqEventPos].type != EventType::EndOfTrack)
{
while (s_trackEvents[trackEventPos].type != EventType::EndOfTrack &&
s_seqEvents[seqEventPos].type != EventType::EndOfTrack) {
if (EventCompare(s_trackEvents[trackEventPos], s_seqEvents[seqEventPos]))
events->push_back(s_trackEvents[trackEventPos++]);
else
@@ -649,14 +583,11 @@ std::unique_ptr<std::vector<Event>> MergeEvents()
return events;
}
void ConvertTimes(std::vector<Event>& events)
{
for (Event& event : events)
{
void ConvertTimes(std::vector<Event>& events) {
for (Event& event : events) {
event.time = (24 * g_clocksPerBeat * event.time) / g_midiTimeDiv;
if (event.type == EventType::Note)
{
if (event.type == EventType::Note) {
event.param1 = g_noteVelocityLUT[event.param1];
std::uint32_t duration = (24 * g_clocksPerBeat * event.param2) / g_midiTimeDiv;
@@ -682,8 +613,7 @@ void insertAtCorrectTimeFromEnd(const std::unique_ptr<std::vector<Event>>& event
events->insert(events->begin(), event);
}
std::unique_ptr<std::vector<Event>> InsertTimingEvents(std::vector<Event>& inEvents)
{
std::unique_ptr<std::vector<Event>> InsertTimingEvents(std::vector<Event>& inEvents) {
std::unique_ptr<std::vector<Event>> outEvents(new std::vector<Event>());
Event timingEvent = {};
@@ -691,18 +621,14 @@ std::unique_ptr<std::vector<Event>> InsertTimingEvents(std::vector<Event>& inEve
timingEvent.type = EventType::TimeSignature;
timingEvent.param2 = 96 * g_clocksPerBeat;
for (const Event& event : inEvents)
{
while (EventCompare(timingEvent, event))
{
for (const Event& event : inEvents) {
while (EventCompare(timingEvent, event)) {
outEvents->push_back(timingEvent);
timingEvent.time += timingEvent.param2;
}
if (event.type == EventType::TimeSignature)
{
if (g_agbTrack == 1 && event.param2 != timingEvent.param2)
{
if (event.type == EventType::TimeSignature) {
if (g_agbTrack == 1 && event.param2 != timingEvent.param2) {
Event originalTimingEvent = event;
originalTimingEvent.type = EventType::OriginalTimeSignature;
outEvents->push_back(originalTimingEvent);
@@ -717,23 +643,19 @@ std::unique_ptr<std::vector<Event>> InsertTimingEvents(std::vector<Event>& inEve
return outEvents;
}
std::unique_ptr<std::vector<Event>> SplitTime(std::vector<Event>& inEvents)
{
std::unique_ptr<std::vector<Event>> SplitTime(std::vector<Event>& inEvents) {
std::unique_ptr<std::vector<Event>> outEvents(new std::vector<Event>());
std::int32_t time = 0;
for (const Event& event : inEvents)
{
for (const Event& event : inEvents) {
std::int32_t diff = event.time - time;
if (diff > 96)
{
if (diff > 96) {
int wholeNoteCount = (diff - 1) / 96;
diff -= 96 * wholeNoteCount;
for (int i = 0; i < wholeNoteCount; i++)
{
for (int i = 0; i < wholeNoteCount; i++) {
time += 96;
Event timeSplitEvent = {};
timeSplitEvent.time = time;
@@ -744,8 +666,7 @@ std::unique_ptr<std::vector<Event>> SplitTime(std::vector<Event>& inEvents)
std::int32_t lutValue = g_noteDurationLUT[diff];
if (lutValue != diff)
{
if (lutValue != diff) {
Event timeSplitEvent = {};
timeSplitEvent.time = time + lutValue;
timeSplitEvent.type = EventType::TimeSplit;
@@ -760,14 +681,11 @@ std::unique_ptr<std::vector<Event>> SplitTime(std::vector<Event>& inEvents)
return outEvents;
}
std::unique_ptr<std::vector<Event>> CreateTies(std::vector<Event>& inEvents)
{
std::unique_ptr<std::vector<Event>> CreateTies(std::vector<Event>& inEvents) {
std::unique_ptr<std::vector<Event>> outEvents(new std::vector<Event>());
for (const Event& event : inEvents)
{
if (event.type == EventType::Note && event.param2 > 96)
{
for (const Event& event : inEvents) {
if (event.type == EventType::Note && event.param2 > 96) {
Event tieEvent = event;
tieEvent.param2 = -1;
insertAtCorrectTimeFromEnd(outEvents, tieEvent);
@@ -779,9 +697,7 @@ std::unique_ptr<std::vector<Event>> CreateTies(std::vector<Event>& inEvents)
// directly insert at the correct position, so it does not need to be sorted later.
// TODO rather keep eotEvent in queue until it's time is reached?
insertAtCorrectTimeFromEnd(outEvents, eotEvent);
}
else
{
} else {
insertAtCorrectTimeFromEnd(outEvents, event);
}
}
@@ -789,25 +705,21 @@ std::unique_ptr<std::vector<Event>> CreateTies(std::vector<Event>& inEvents)
return outEvents;
}
void CalculateWaits(std::vector<Event>& events)
{
void CalculateWaits(std::vector<Event>& events) {
g_initialWait = events[0].time;
int wholeNoteCount = 0;
for (unsigned i = 0; i < events.size() && events[i].type != EventType::EndOfTrack; i++)
{
for (unsigned i = 0; i < events.size() && events[i].type != EventType::EndOfTrack; i++) {
events[i].time = events[i + 1].time - events[i].time;
if (events[i].type == EventType::TimeSignature)
{
if (events[i].type == EventType::TimeSignature) {
events[i].type = EventType::WholeNoteMark;
events[i].param2 = wholeNoteCount++;
}
}
}
int CalculateCompressionScore(std::vector<Event>& events, int index)
{
int CalculateCompressionScore(std::vector<Event>& events, int index) {
int score = 0;
std::uint8_t lastParam1 = events[index].param1;
std::uint8_t lastVelocity = 0x80u;
@@ -818,28 +730,23 @@ int CalculateCompressionScore(std::vector<Event>& events, int index)
if (events[index].time > 0)
score++;
for (int i = index + 1; !IsPatternBoundary(events[i].type); i++)
{
if (events[i].type == EventType::Note)
{
for (int i = index + 1; !IsPatternBoundary(events[i].type); i++) {
if (events[i].type == EventType::Note) {
int val = 0;
if (events[i].note != lastNote)
{
if (events[i].note != lastNote) {
val++;
lastNote = events[i].note;
}
if (events[i].param1 != lastVelocity)
{
if (events[i].param1 != lastVelocity) {
val++;
lastVelocity = events[i].param1;
}
std::int32_t duration = events[i].param2;
if (g_noteDurationLUT[duration] != lastDuration)
{
if (g_noteDurationLUT[duration] != lastDuration) {
val++;
lastDuration = g_noteDurationLUT[duration];
}
@@ -851,24 +758,17 @@ int CalculateCompressionScore(std::vector<Event>& events, int index)
val = 1;
score += val;
}
else
{
} else {
lastDuration = 0x80000000;
if (events[i].type == lastType)
{
if ((lastType != EventType::Controller && (int)lastType != 0x25 && lastType != EventType::EndOfTie) || events[i].param1 == lastParam1)
{
if (events[i].type == lastType) {
if ((lastType != EventType::Controller && (int)lastType != 0x25 && lastType != EventType::EndOfTie) ||
events[i].param1 == lastParam1) {
score++;
}
else
{
} else {
score += 2;
}
}
else
{
} else {
score += 2;
}
}
@@ -883,19 +783,15 @@ int CalculateCompressionScore(std::vector<Event>& events, int index)
return score;
}
bool IsCompressionMatch(std::vector<Event>& events, int index1, int index2)
{
if (events[index1].type != events[index2].type ||
events[index1].note != events[index2].note ||
events[index1].param1 != events[index2].param1 ||
events[index1].time != events[index2].time)
bool IsCompressionMatch(std::vector<Event>& events, int index1, int index2) {
if (events[index1].type != events[index2].type || events[index1].note != events[index2].note ||
events[index1].param1 != events[index2].param1 || events[index1].time != events[index2].time)
return false;
index1++;
index2++;
do
{
do {
if (events[index1] != events[index2])
return false;
@@ -906,20 +802,16 @@ bool IsCompressionMatch(std::vector<Event>& events, int index1, int index2)
return IsPatternBoundary(events[index2].type);
}
void CompressWholeNote(std::vector<Event>& events, int index)
{
for (int j = index + 1; events[j].type != EventType::EndOfTrack; j++)
{
while (events[j].type != EventType::WholeNoteMark)
{
void CompressWholeNote(std::vector<Event>& events, int index) {
for (int j = index + 1; events[j].type != EventType::EndOfTrack; j++) {
while (events[j].type != EventType::WholeNoteMark) {
j++;
if (events[j].type == EventType::EndOfTrack)
return;
}
if (IsCompressionMatch(events, index, j))
{
if (IsCompressionMatch(events, index, j)) {
events[j].type = EventType::Pattern;
events[j].param2 = events[index].param2 & 0x7FFFFFFF;
events[index].param2 |= 0x80000000;
@@ -927,27 +819,22 @@ void CompressWholeNote(std::vector<Event>& events, int index)
}
}
void Compress(std::vector<Event>& events)
{
for (int i = 0; events[i].type != EventType::EndOfTrack; i++)
{
while (events[i].type != EventType::WholeNoteMark)
{
void Compress(std::vector<Event>& events) {
for (int i = 0; events[i].type != EventType::EndOfTrack; i++) {
while (events[i].type != EventType::WholeNoteMark) {
i++;
if (events[i].type == EventType::EndOfTrack)
return;
}
if (CalculateCompressionScore(events, i) >= 6)
{
if (CalculateCompressionScore(events, i) >= 6) {
CompressWholeNote(events, i);
}
}
}
void ReadMidiTracks()
{
void ReadMidiTracks() {
long trackHeaderStart = 14;
ReadMidiTrackHeader(trackHeaderStart);
@@ -955,16 +842,13 @@ void ReadMidiTracks()
g_agbTrack = 1;
for (int midiTrack = 0; midiTrack < g_midiTrackCount; midiTrack++)
{
for (int midiTrack = 0; midiTrack < g_midiTrackCount; midiTrack++) {
trackHeaderStart += ReadMidiTrackHeader(trackHeaderStart);
for (g_midiChan = 0; g_midiChan < 16; g_midiChan++)
{
for (g_midiChan = 0; g_midiChan < 16; g_midiChan++) {
ReadTrackEvents();
if (s_minNote != 0xFF)
{
if (s_minNote != 0xFF) {
#ifdef DEBUG
printf("Track%d = Midi-Ch.%d\n", g_agbTrack, g_midiChan + 1);
#endif
@@ -972,9 +856,9 @@ void ReadMidiTracks()
std::unique_ptr<std::vector<Event>> events(MergeEvents());
// We don't need TEMPO in anything but track 1.
if (g_agbTrack == 1)
{
auto it = std::remove_if(s_seqEvents.begin(), s_seqEvents.end(), [](const Event& event) { return event.type == EventType::Tempo; });
if (g_agbTrack == 1) {
auto it = std::remove_if(s_seqEvents.begin(), s_seqEvents.end(),
[](const Event& event) { return event.type == EventType::Tempo; });
s_seqEvents.erase(it, s_seqEvents.end());
}
Executable → Regular
+8 -20
View File
@@ -23,14 +23,9 @@
#include <cstdint>
enum class MidiFormat
{
SingleTrack,
MultiTrack
};
enum class MidiFormat { SingleTrack, MultiTrack };
enum class EventType
{
enum class EventType {
EndOfTie = 0x01,
Label = 0x11,
LoopEnd = 0x38, // To place it last if at the same time as other meta events, but before notes on the same frame
@@ -50,25 +45,19 @@ enum class EventType
EndOfTrack = 0xFF,
};
struct Event
{
struct Event {
std::int32_t time;
EventType type;
std::uint8_t note;
std::uint8_t param1;
std::int32_t param2;
bool operator==(const Event& other)
{
return (time == other.time
&& type == other.type
&& note == other.note
&& param1 == other.param1
&& param2 == other.param2);
bool operator==(const Event& other) {
return (time == other.time && type == other.type && note == other.note && param1 == other.param1 &&
param2 == other.param2);
}
bool operator!=(const Event& other)
{
bool operator!=(const Event& other) {
return !(*this == other);
}
};
@@ -79,8 +68,7 @@ void ReadMidiTracks();
extern int g_midiChan;
extern std::int32_t g_initialWait;
inline bool IsPatternBoundary(EventType type)
{
inline bool IsPatternBoundary(EventType type) {
return type == EventType::EndOfTrack || (int)type <= 0x17;
}
Executable → Regular
+115 -139
View File
@@ -20,18 +20,17 @@
#include "tables.h"
const int g_noteDurationLUT[] =
{
0, // 0
1, // 1
2, // 2
3, // 3
4, // 4
5, // 5
6, // 6
7, // 7
8, // 8
9, // 9
const int g_noteDurationLUT[] = {
0, // 0
1, // 1
2, // 2
3, // 3
4, // 4
5, // 5
6, // 6
7, // 7
8, // 8
9, // 9
10, // 10
11, // 11
12, // 12
@@ -121,105 +120,104 @@ const int g_noteDurationLUT[] =
96, // 96
};
const int g_noteVelocityLUT[] =
{
0, // 0
4, // 1
4, // 2
4, // 3
4, // 4
8, // 5
8, // 6
8, // 7
8, // 8
12, // 9
12, // 10
12, // 11
12, // 12
16, // 13
16, // 14
16, // 15
16, // 16
20, // 17
20, // 18
20, // 19
20, // 20
24, // 21
24, // 22
24, // 23
24, // 24
28, // 25
28, // 26
28, // 27
28, // 28
32, // 29
32, // 30
32, // 31
32, // 32
36, // 33
36, // 34
36, // 35
36, // 36
40, // 37
40, // 38
40, // 39
40, // 40
44, // 41
44, // 42
44, // 43
44, // 44
48, // 45
48, // 46
48, // 47
48, // 48
52, // 49
52, // 50
52, // 51
52, // 52
56, // 53
56, // 54
56, // 55
56, // 56
60, // 57
60, // 58
60, // 59
60, // 60
64, // 61
64, // 62
64, // 63
64, // 64
68, // 65
68, // 66
68, // 67
68, // 68
72, // 69
72, // 70
72, // 71
72, // 72
76, // 73
76, // 74
76, // 75
76, // 76
80, // 77
80, // 78
80, // 79
80, // 80
84, // 81
84, // 82
84, // 83
84, // 84
88, // 85
88, // 86
88, // 87
88, // 88
92, // 89
92, // 90
92, // 91
92, // 92
96, // 93
96, // 94
96, // 95
96, // 96
const int g_noteVelocityLUT[] = {
0, // 0
4, // 1
4, // 2
4, // 3
4, // 4
8, // 5
8, // 6
8, // 7
8, // 8
12, // 9
12, // 10
12, // 11
12, // 12
16, // 13
16, // 14
16, // 15
16, // 16
20, // 17
20, // 18
20, // 19
20, // 20
24, // 21
24, // 22
24, // 23
24, // 24
28, // 25
28, // 26
28, // 27
28, // 28
32, // 29
32, // 30
32, // 31
32, // 32
36, // 33
36, // 34
36, // 35
36, // 36
40, // 37
40, // 38
40, // 39
40, // 40
44, // 41
44, // 42
44, // 43
44, // 44
48, // 45
48, // 46
48, // 47
48, // 48
52, // 49
52, // 50
52, // 51
52, // 52
56, // 53
56, // 54
56, // 55
56, // 56
60, // 57
60, // 58
60, // 59
60, // 60
64, // 61
64, // 62
64, // 63
64, // 64
68, // 65
68, // 66
68, // 67
68, // 68
72, // 69
72, // 70
72, // 71
72, // 72
76, // 73
76, // 74
76, // 75
76, // 76
80, // 77
80, // 78
80, // 79
80, // 80
84, // 81
84, // 82
84, // 83
84, // 84
88, // 85
88, // 86
88, // 87
88, // 88
92, // 89
92, // 90
92, // 91
92, // 92
96, // 93
96, // 94
96, // 95
96, // 96
100, // 97
100, // 98
100, // 99
@@ -253,34 +251,12 @@ const int g_noteVelocityLUT[] =
127, // 127
};
const char* g_noteTable[] =
{
"Cn%01u ",
"Cs%01u ",
"Dn%01u ",
"Ds%01u ",
"En%01u ",
"Fn%01u ",
"Fs%01u ",
"Gn%01u ",
"Gs%01u ",
"An%01u ",
"As%01u ",
"Bn%01u ",
const char* g_noteTable[] = {
"Cn%01u ", "Cs%01u ", "Dn%01u ", "Ds%01u ", "En%01u ", "Fn%01u ",
"Fs%01u ", "Gn%01u ", "Gs%01u ", "An%01u ", "As%01u ", "Bn%01u ",
};
const char* g_minusNoteTable[] =
{
"CnM%01u",
"CsM%01u",
"DnM%01u",
"DsM%01u",
"EnM%01u",
"FnM%01u",
"FsM%01u",
"GnM%01u",
"GsM%01u",
"AnM%01u",
"AsM%01u",
"BnM%01u",
const char* g_minusNoteTable[] = {
"CnM%01u", "CsM%01u", "DnM%01u", "DsM%01u", "EnM%01u", "FnM%01u",
"FsM%01u", "GnM%01u", "GsM%01u", "AnM%01u", "AsM%01u", "BnM%01u",
};
Executable → Regular
+69 -165
View File
@@ -27,9 +27,8 @@
#include "utf8.h"
#include "string_parser.h"
AsmFile::AsmFile(std::string filename) : m_filename(filename)
{
FILE *fp = std::fopen(filename.c_str(), "rb");
AsmFile::AsmFile(std::string filename) : m_filename(filename) {
FILE* fp = std::fopen(filename.c_str(), "rb");
if (fp == NULL) {
// The include might be an asset.
@@ -64,8 +63,7 @@ AsmFile::AsmFile(std::string filename) : m_filename(filename)
RemoveComments();
}
AsmFile::AsmFile(AsmFile&& other) : m_filename(std::move(other.m_filename))
{
AsmFile::AsmFile(AsmFile&& other) : m_filename(std::move(other.m_filename)) {
m_buffer = other.m_buffer;
m_pos = other.m_pos;
m_size = other.m_size;
@@ -75,8 +73,7 @@ AsmFile::AsmFile(AsmFile&& other) : m_filename(std::move(other.m_filename))
other.m_buffer = nullptr;
}
AsmFile::~AsmFile()
{
AsmFile::~AsmFile() {
delete[] m_buffer;
}
@@ -84,60 +81,44 @@ AsmFile::~AsmFile()
// It stops upon encountering a null character,
// which may or may not be the end of file marker.
// If it's not, the error will be caught later.
void AsmFile::RemoveComments()
{
void AsmFile::RemoveComments() {
long pos = 0;
char stringChar = 0;
for (;;)
{
for (;;) {
if (m_buffer[pos] == 0)
return;
if (stringChar != 0)
{
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == stringChar)
{
if (stringChar != 0) {
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == stringChar) {
pos += 2;
}
else
{
} else {
if (m_buffer[pos] == stringChar)
stringChar = 0;
pos++;
}
}
else if (m_buffer[pos] == '@' && (pos == 0 || m_buffer[pos - 1] != '\\'))
{
} else if (m_buffer[pos] == '@' && (pos == 0 || m_buffer[pos - 1] != '\\')) {
while (m_buffer[pos] != '\n' && m_buffer[pos] != 0)
m_buffer[pos++] = ' ';
}
else if (m_buffer[pos] == '/' && m_buffer[pos + 1] == '*')
{
} else if (m_buffer[pos] == '/' && m_buffer[pos + 1] == '*') {
m_buffer[pos++] = ' ';
m_buffer[pos++] = ' ';
for (;;)
{
for (;;) {
if (m_buffer[pos] == 0)
return;
if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/')
{
if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/') {
m_buffer[pos++] = ' ';
m_buffer[pos++] = ' ';
break;
}
else
{
} else {
if (m_buffer[pos] != '\n')
m_buffer[pos] = ' ';
pos++;
}
}
}
else
{
} else {
if (m_buffer[pos] == '"' || m_buffer[pos] == '\'')
stringChar = m_buffer[pos];
pos++;
@@ -147,8 +128,7 @@ void AsmFile::RemoveComments()
// Checks if we're at a particular directive and if so, consumes it.
// Returns whether the directive was found.
bool AsmFile::CheckForDirective(std::string name)
{
bool AsmFile::CheckForDirective(std::string name) {
long i;
long length = static_cast<long>(name.length());
@@ -166,8 +146,7 @@ bool AsmFile::CheckForDirective(std::string name)
// Checks if we're at a known directive and if so, consumes it.
// Returns which directive was found.
Directive AsmFile::GetDirective()
{
Directive AsmFile::GetDirective() {
SkipWhitespace();
if (CheckForDirective(".include"))
@@ -182,21 +161,18 @@ Directive AsmFile::GetDirective()
// Checks if we're at label that ends with '::'.
// Returns the name if so and an empty string if not.
std::string AsmFile::GetGlobalLabel()
{
std::string AsmFile::GetGlobalLabel() {
long start = m_pos;
long pos = m_pos;
if (IsIdentifierStartingChar(m_buffer[pos]))
{
if (IsIdentifierStartingChar(m_buffer[pos])) {
pos++;
while (IsIdentifierChar(m_buffer[pos]))
pos++;
}
if (m_buffer[pos] == ':' && m_buffer[pos + 1] == ':')
{
if (m_buffer[pos] == ':' && m_buffer[pos + 1] == ':') {
m_pos = pos + 2;
ExpectEmptyRestOfLine();
return std::string(&m_buffer[start], pos - start);
@@ -206,15 +182,13 @@ std::string AsmFile::GetGlobalLabel()
}
// Skips tabs and spaces.
void AsmFile::SkipWhitespace()
{
void AsmFile::SkipWhitespace() {
while (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
m_pos++;
}
// Reads include path.
std::string AsmFile::ReadPath()
{
std::string AsmFile::ReadPath() {
SkipWhitespace();
if (m_buffer[m_pos] != '"')
@@ -225,12 +199,10 @@ std::string AsmFile::ReadPath()
int length = 0;
long startPos = m_pos;
while (m_buffer[m_pos] != '"')
{
while (m_buffer[m_pos] != '"') {
unsigned char c = m_buffer[m_pos++];
if (c == 0)
{
if (c == 0) {
if (m_pos >= m_size)
RaiseError("unexpected EOF in include string");
else
@@ -241,8 +213,7 @@ std::string AsmFile::ReadPath()
RaiseError("unexpected character '\\x%02X' in include string", c);
// Don't bother allowing any escape sequences.
if (c == '\\')
{
if (c == '\\') {
c = m_buffer[m_pos];
RaiseError("unexpected escape '\\%c' in include string", c);
}
@@ -261,31 +232,23 @@ std::string AsmFile::ReadPath()
}
// Reads a charmap string.
int AsmFile::ReadString(unsigned char* s)
{
int AsmFile::ReadString(unsigned char* s) {
SkipWhitespace();
int length;
StringParser stringParser(m_buffer, m_size);
try
{
try {
m_pos += stringParser.ParseString(m_pos, s, length);
}
catch (std::runtime_error& e)
{
RaiseError(e.what());
}
} catch (std::runtime_error& e) { RaiseError(e.what()); }
SkipWhitespace();
if (ConsumeComma())
{
if (ConsumeComma()) {
SkipWhitespace();
int padLength = ReadPadLength();
while (length < padLength)
{
while (length < padLength) {
s[length++] = 0;
}
}
@@ -295,40 +258,13 @@ int AsmFile::ReadString(unsigned char* s)
return length;
}
int AsmFile::ReadBraille(unsigned char* s)
{
static std::map<char, unsigned char> encoding =
{
{ 'A', 0x01 },
{ 'B', 0x05 },
{ 'C', 0x03 },
{ 'D', 0x0B },
{ 'E', 0x09 },
{ 'F', 0x07 },
{ 'G', 0x0F },
{ 'H', 0x0D },
{ 'I', 0x06 },
{ 'J', 0x0E },
{ 'K', 0x11 },
{ 'L', 0x15 },
{ 'M', 0x13 },
{ 'N', 0x1B },
{ 'O', 0x19 },
{ 'P', 0x17 },
{ 'Q', 0x1F },
{ 'R', 0x1D },
{ 'S', 0x16 },
{ 'T', 0x1E },
{ 'U', 0x31 },
{ 'V', 0x35 },
{ 'W', 0x2E },
{ 'X', 0x33 },
{ 'Y', 0x3B },
{ 'Z', 0x39 },
{ ' ', 0x00 },
{ ',', 0x04 },
{ '.', 0x2C },
{ '$', 0xFF },
int AsmFile::ReadBraille(unsigned char* s) {
static std::map<char, unsigned char> encoding = {
{ 'A', 0x01 }, { 'B', 0x05 }, { 'C', 0x03 }, { 'D', 0x0B }, { 'E', 0x09 }, { 'F', 0x07 },
{ 'G', 0x0F }, { 'H', 0x0D }, { 'I', 0x06 }, { 'J', 0x0E }, { 'K', 0x11 }, { 'L', 0x15 },
{ 'M', 0x13 }, { 'N', 0x1B }, { 'O', 0x19 }, { 'P', 0x17 }, { 'Q', 0x1F }, { 'R', 0x1D },
{ 'S', 0x16 }, { 'T', 0x1E }, { 'U', 0x31 }, { 'V', 0x35 }, { 'W', 0x2E }, { 'X', 0x33 },
{ 'Y', 0x3B }, { 'Z', 0x39 }, { ' ', 0x00 }, { ',', 0x04 }, { '.', 0x2C }, { '$', 0xFF },
};
SkipWhitespace();
@@ -340,22 +276,17 @@ int AsmFile::ReadBraille(unsigned char* s)
m_pos++;
while (m_buffer[m_pos] != '"')
{
while (m_buffer[m_pos] != '"') {
if (length == kMaxStringLength)
RaiseError("mapped string longer than %d bytes", kMaxStringLength);
if (m_buffer[m_pos] == '\\' && m_buffer[m_pos + 1] == 'n')
{
if (m_buffer[m_pos] == '\\' && m_buffer[m_pos + 1] == 'n') {
s[length++] = 0xFE;
m_pos += 2;
}
else
{
} else {
char c = m_buffer[m_pos];
if (encoding.count(c) == 0)
{
if (encoding.count(c) == 0) {
if (IsAsciiPrintable(c))
RaiseError("character '%c' not valid in braille string", m_buffer[m_pos]);
else
@@ -376,10 +307,8 @@ int AsmFile::ReadBraille(unsigned char* s)
// If we're at a comma, consumes it.
// Returns whether a comma was found.
bool AsmFile::ConsumeComma()
{
if (m_buffer[m_pos] == ',')
{
bool AsmFile::ConsumeComma() {
if (m_buffer[m_pos] == ',') {
m_pos++;
return true;
}
@@ -388,8 +317,7 @@ bool AsmFile::ConsumeComma()
}
// Converts digit character to numerical value.
static int ConvertDigit(char c, int radix)
{
static int ConvertDigit(char c, int radix) {
int digit;
if (c >= '0' && c <= '9')
@@ -405,15 +333,13 @@ static int ConvertDigit(char c, int radix)
}
// Reads an integer. If the integer is greater than maxValue, it returns -1.
int AsmFile::ReadPadLength()
{
int AsmFile::ReadPadLength() {
if (!IsAsciiDigit(m_buffer[m_pos]))
RaiseError("expected integer");
int radix = 10;
if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x')
{
if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x') {
radix = 16;
m_pos += 2;
}
@@ -421,8 +347,7 @@ int AsmFile::ReadPadLength()
unsigned n = 0;
int digit;
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1)
{
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1) {
n = n * radix + digit;
if (n > kMaxStringLength)
@@ -435,25 +360,18 @@ int AsmFile::ReadPadLength()
}
// Outputs the current line and moves to the next one.
void AsmFile::OutputLine()
{
void AsmFile::OutputLine() {
while (m_buffer[m_pos] != '\n' && m_buffer[m_pos] != 0)
m_pos++;
if (m_buffer[m_pos] == 0)
{
if (m_pos >= m_size)
{
if (m_buffer[m_pos] == 0) {
if (m_pos >= m_size) {
RaiseWarning("file doesn't end with newline");
puts(&m_buffer[m_lineStart]);
}
else
{
} else {
RaiseError("unexpected null character");
}
}
else
{
} else {
m_buffer[m_pos] = 0;
puts(&m_buffer[m_lineStart]);
m_buffer[m_pos] = '\n';
@@ -464,72 +382,58 @@ void AsmFile::OutputLine()
}
// Asserts that the rest of the line is empty and moves to the next one.
void AsmFile::ExpectEmptyRestOfLine()
{
void AsmFile::ExpectEmptyRestOfLine() {
SkipWhitespace();
if (m_buffer[m_pos] == 0)
{
if (m_buffer[m_pos] == 0) {
if (m_pos >= m_size)
RaiseWarning("file doesn't end with newline");
else
RaiseError("unexpected null character");
}
else if (m_buffer[m_pos] == '\n')
{
} else if (m_buffer[m_pos] == '\n') {
m_pos++;
m_lineStart = m_pos;
m_lineNum++;
}
else if (m_buffer[m_pos] == '\r')
{
} else if (m_buffer[m_pos] == '\r') {
RaiseError("only Unix-style LF newlines are supported");
}
else
{
} else {
RaiseError("junk at end of line");
}
}
// Checks if we're at the end of the file.
bool AsmFile::IsAtEnd()
{
bool AsmFile::IsAtEnd() {
return (m_pos >= m_size);
}
// Output the current location to set gas's logical file and line numbers.
void AsmFile::OutputLocation()
{
void AsmFile::OutputLocation() {
std::printf("# %ld \"%s\"\n", m_lineNum, m_filename.c_str());
}
// Reports a diagnostic message.
void AsmFile::ReportDiagnostic(const char* type, const char* format, std::va_list args)
{
void AsmFile::ReportDiagnostic(const char* type, const char* format, std::va_list args) {
const int bufferSize = 1024;
char buffer[bufferSize];
std::vsnprintf(buffer, bufferSize, format, args);
std::fprintf(stderr, "%s:%ld: %s: %s\n", m_filename.c_str(), m_lineNum, type, buffer);
}
#define DO_REPORT(type) \
do \
{ \
std::va_list args; \
va_start(args, format); \
ReportDiagnostic(type, format, args); \
va_end(args); \
} while (0)
#define DO_REPORT(type) \
do { \
std::va_list args; \
va_start(args, format); \
ReportDiagnostic(type, format, args); \
va_end(args); \
} while (0)
// Reports an error diagnostic and terminates the program.
void AsmFile::RaiseError(const char* format, ...)
{
void AsmFile::RaiseError(const char* format, ...) {
DO_REPORT("error");
std::exit(1);
}
// Reports a warning diagnostic.
void AsmFile::RaiseWarning(const char* format, ...)
{
void AsmFile::RaiseWarning(const char* format, ...) {
DO_REPORT("warning");
}
Executable → Regular
+4 -11
View File
@@ -26,17 +26,10 @@
#include <string>
#include "preproc.h"
enum class Directive
{
Include,
String,
Braille,
Unknown
};
enum class Directive { Include, String, Braille, Unknown };
class AsmFile
{
public:
class AsmFile {
public:
AsmFile(std::string filename);
AsmFile(AsmFile&& other);
AsmFile(const AsmFile&) = delete;
@@ -50,7 +43,7 @@ public:
void OutputLine();
void OutputLocation();
private:
private:
char* m_buffer;
long m_pos;
long m_size;
Executable → Regular
+58 -111
View File
@@ -29,9 +29,8 @@
#include "utf8.h"
#include "string_parser.h"
CFile::CFile(std::string filename) : m_filename(filename)
{
FILE *fp = std::fopen(filename.c_str(), "rb");
CFile::CFile(std::string filename) : m_filename(filename) {
FILE* fp = std::fopen(filename.c_str(), "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str());
@@ -58,8 +57,7 @@ CFile::CFile(std::string filename) : m_filename(filename)
m_lineNum = 1;
}
CFile::CFile(CFile&& other) : m_filename(std::move(other.m_filename))
{
CFile::CFile(CFile&& other) : m_filename(std::move(other.m_filename)) {
m_buffer = other.m_buffer;
m_pos = other.m_pos;
m_size = other.m_size;
@@ -68,41 +66,30 @@ CFile::CFile(CFile&& other) : m_filename(std::move(other.m_filename))
other.m_buffer = nullptr;
}
CFile::~CFile()
{
CFile::~CFile() {
delete[] m_buffer;
}
void CFile::Preproc()
{
void CFile::Preproc() {
char stringChar = 0;
while (m_pos < m_size)
{
if (stringChar)
{
if (m_buffer[m_pos] == stringChar)
{
while (m_pos < m_size) {
if (stringChar) {
if (m_buffer[m_pos] == stringChar) {
std::putchar(stringChar);
m_pos++;
stringChar = 0;
}
else if (m_buffer[m_pos] == '\\' && m_buffer[m_pos + 1] == stringChar)
{
} else if (m_buffer[m_pos] == '\\' && m_buffer[m_pos + 1] == stringChar) {
std::putchar('\\');
std::putchar(stringChar);
m_pos += 2;
}
else
{
} else {
if (m_buffer[m_pos] == '\n')
m_lineNum++;
std::putchar(m_buffer[m_pos]);
m_pos++;
}
}
else
{
} else {
TryConvertString();
TryConvertIncbin();
@@ -123,10 +110,8 @@ void CFile::Preproc()
}
}
bool CFile::ConsumeHorizontalWhitespace()
{
if (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
{
bool CFile::ConsumeHorizontalWhitespace() {
if (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ') {
m_pos++;
return true;
}
@@ -134,18 +119,15 @@ bool CFile::ConsumeHorizontalWhitespace()
return false;
}
bool CFile::ConsumeNewline()
{
if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n')
{
bool CFile::ConsumeNewline() {
if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n') {
m_pos += 2;
m_lineNum++;
std::putchar('\n');
return true;
}
if (m_buffer[m_pos] == '\n')
{
if (m_buffer[m_pos] == '\n') {
m_pos++;
m_lineNum++;
std::putchar('\n');
@@ -155,14 +137,12 @@ bool CFile::ConsumeNewline()
return false;
}
void CFile::SkipWhitespace()
{
void CFile::SkipWhitespace() {
while (ConsumeHorizontalWhitespace() || ConsumeNewline())
;
}
void CFile::TryConvertString()
{
void CFile::TryConvertString() {
long oldPos = m_pos;
long oldLineNum = m_lineNum;
bool noTerminator = false;
@@ -172,16 +152,14 @@ void CFile::TryConvertString()
m_pos++;
if (m_buffer[m_pos] == '_')
{
if (m_buffer[m_pos] == '_') {
noTerminator = true;
m_pos++;
}
SkipWhitespace();
if (m_buffer[m_pos] != '(')
{
if (m_buffer[m_pos] != '(') {
m_pos = oldPos;
m_lineNum = oldLineNum;
return;
@@ -193,35 +171,24 @@ void CFile::TryConvertString()
std::printf("{ ");
while (1)
{
while (1) {
SkipWhitespace();
if (m_buffer[m_pos] == '"')
{
if (m_buffer[m_pos] == '"') {
unsigned char s[kMaxStringLength];
int length;
StringParser stringParser(m_buffer, m_size);
try
{
try {
m_pos += stringParser.ParseString(m_pos, s, length);
}
catch (std::runtime_error& e)
{
RaiseError(e.what());
}
} catch (std::runtime_error& e) { RaiseError(e.what()); }
for (int i = 0; i < length; i++)
printf("0x%02X, ", s[i]);
}
else if (m_buffer[m_pos] == ')')
{
} else if (m_buffer[m_pos] == ')') {
m_pos++;
break;
}
else
{
} else {
if (m_pos >= m_size)
RaiseError("unexpected EOF");
if (IsAsciiPrintable(m_buffer[m_pos]))
@@ -237,8 +204,7 @@ void CFile::TryConvertString()
std::printf("0xFF }");
}
bool CFile::CheckIdentifier(const std::string& ident)
{
bool CFile::CheckIdentifier(const std::string& ident) {
unsigned int i;
for (i = 0; i < ident.length() && m_pos + i < (unsigned)m_size; i++)
@@ -248,8 +214,7 @@ bool CFile::CheckIdentifier(const std::string& ident)
return (i == ident.length());
}
std::unique_ptr<unsigned char[]> CFile::ReadWholeFile(const std::string& path, int& size)
{
std::unique_ptr<unsigned char[]> CFile::ReadWholeFile(const std::string& path, int& size) {
FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == nullptr)
@@ -271,34 +236,25 @@ std::unique_ptr<unsigned char[]> CFile::ReadWholeFile(const std::string& path, i
return buffer;
}
int ExtractData(const std::unique_ptr<unsigned char[]>& buffer, int offset, int size)
{
switch (size)
{
case 1:
return buffer[offset];
case 2:
return (buffer[offset + 1] << 8)
| buffer[offset];
case 4:
return (buffer[offset + 3] << 24)
| (buffer[offset + 2] << 16)
| (buffer[offset + 1] << 8)
| buffer[offset];
default:
FATAL_ERROR("Invalid size passed to ExtractData.\n");
int ExtractData(const std::unique_ptr<unsigned char[]>& buffer, int offset, int size) {
switch (size) {
case 1:
return buffer[offset];
case 2:
return (buffer[offset + 1] << 8) | buffer[offset];
case 4:
return (buffer[offset + 3] << 24) | (buffer[offset + 2] << 16) | (buffer[offset + 1] << 8) | buffer[offset];
default:
FATAL_ERROR("Invalid size passed to ExtractData.\n");
}
}
void CFile::TryConvertIncbin()
{
void CFile::TryConvertIncbin() {
std::string idents[6] = { "INCBIN_S8", "INCBIN_U8", "INCBIN_S16", "INCBIN_U16", "INCBIN_S32", "INCBIN_U32" };
int incbinType = -1;
for (int i = 0; i < 6; i++)
{
if (CheckIdentifier(idents[i]))
{
for (int i = 0; i < 6; i++) {
if (CheckIdentifier(idents[i])) {
incbinType = i;
break;
}
@@ -317,8 +273,7 @@ void CFile::TryConvertIncbin()
SkipWhitespace();
if (m_buffer[m_pos] != '(')
{
if (m_buffer[m_pos] != '(') {
m_pos = oldPos;
m_lineNum = oldLineNum;
return;
@@ -328,8 +283,7 @@ void CFile::TryConvertIncbin()
std::printf("{");
while (true)
{
while (true) {
SkipWhitespace();
if (m_buffer[m_pos] != '"')
@@ -339,10 +293,8 @@ void CFile::TryConvertIncbin()
int startPos = m_pos;
while (m_buffer[m_pos] != '"')
{
if (m_buffer[m_pos] == 0)
{
while (m_buffer[m_pos] != '"') {
if (m_buffer[m_pos] == 0) {
if (m_pos >= m_size)
RaiseError("unexpected EOF in path string");
else
@@ -354,7 +306,7 @@ void CFile::TryConvertIncbin()
if (m_buffer[m_pos] == '\\')
RaiseError("unexpected escape in path string");
m_pos++;
}
@@ -371,8 +323,7 @@ void CFile::TryConvertIncbin()
int count = fileSize / size;
int offset = 0;
for (int i = 0; i < count; i++)
{
for (int i = 0; i < count; i++) {
int data = ExtractData(buffer, offset, size);
offset += size;
@@ -389,7 +340,7 @@ void CFile::TryConvertIncbin()
m_pos++;
}
if (m_buffer[m_pos] != ')')
RaiseError("expected ')'");
@@ -399,32 +350,28 @@ void CFile::TryConvertIncbin()
}
// Reports a diagnostic message.
void CFile::ReportDiagnostic(const char* type, const char* format, std::va_list args)
{
void CFile::ReportDiagnostic(const char* type, const char* format, std::va_list args) {
const int bufferSize = 1024;
char buffer[bufferSize];
std::vsnprintf(buffer, bufferSize, format, args);
std::fprintf(stderr, "%s:%ld: %s: %s\n", m_filename.c_str(), m_lineNum, type, buffer);
}
#define DO_REPORT(type) \
do \
{ \
std::va_list args; \
va_start(args, format); \
ReportDiagnostic(type, format, args); \
va_end(args); \
} while (0)
#define DO_REPORT(type) \
do { \
std::va_list args; \
va_start(args, format); \
ReportDiagnostic(type, format, args); \
va_end(args); \
} while (0)
// Reports an error diagnostic and terminates the program.
void CFile::RaiseError(const char* format, ...)
{
void CFile::RaiseError(const char* format, ...) {
DO_REPORT("error");
std::exit(1);
}
// Reports a warning diagnostic.
void CFile::RaiseWarning(const char* format, ...)
{
void CFile::RaiseWarning(const char* format, ...) {
DO_REPORT("warning");
}
Executable → Regular
+3 -4
View File
@@ -27,16 +27,15 @@
#include <memory>
#include "preproc.h"
class CFile
{
public:
class CFile {
public:
CFile(std::string filename);
CFile(CFile&& other);
CFile(const CFile&) = delete;
~CFile();
void Preproc();
private:
private:
char* m_buffer;
long m_pos;
long m_size;
Executable → Regular
+9 -19
View File
@@ -24,47 +24,37 @@
#include <cstdint>
#include <cassert>
inline bool IsAscii(unsigned char c)
{
inline bool IsAscii(unsigned char c) {
return (c < 128);
}
inline bool IsAsciiAlpha(unsigned char c)
{
inline bool IsAsciiAlpha(unsigned char c) {
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
}
inline bool IsAsciiDigit(unsigned char c)
{
inline bool IsAsciiDigit(unsigned char c) {
return (c >= '0' && c <= '9');
}
inline bool IsAsciiHexDigit(unsigned char c)
{
return ((c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F'));
inline bool IsAsciiHexDigit(unsigned char c) {
return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
inline bool IsAsciiAlphanum(unsigned char c)
{
inline bool IsAsciiAlphanum(unsigned char c) {
return (IsAsciiAlpha(c) || IsAsciiDigit(c));
}
inline bool IsAsciiPrintable(unsigned char c)
{
inline bool IsAsciiPrintable(unsigned char c) {
return (c >= ' ' && c <= '~');
}
// Returns whether the character can start a C identifier or the identifier of a "{FOO}" constant in strings.
inline bool IsIdentifierStartingChar(unsigned char c)
{
inline bool IsIdentifierStartingChar(unsigned char c) {
return IsAsciiAlpha(c) || c == '_';
}
// Returns whether the character can be used in a C identifier or the identifier of a "{FOO}" constant in strings.
inline bool IsIdentifierChar(unsigned char c)
{
inline bool IsIdentifierChar(unsigned char c) {
return IsAsciiAlphanum(c) || c == '_';
}
Executable → Regular
+73 -133
View File
@@ -26,24 +26,16 @@
#include "char_util.h"
#include "utf8.h"
enum LhsType
{
Char,
Escape,
Constant,
None
};
enum LhsType { Char, Escape, Constant, None };
struct Lhs
{
struct Lhs {
LhsType type;
std::string name;
std::int32_t code;
};
class CharmapReader
{
public:
class CharmapReader {
public:
CharmapReader(std::string filename);
CharmapReader(const CharmapReader&) = delete;
~CharmapReader();
@@ -53,7 +45,7 @@ public:
void ExpectEmptyRestOfLine();
void RaiseError(const char* format, ...);
private:
private:
char* m_buffer;
long m_pos;
long m_size;
@@ -65,17 +57,15 @@ private:
void SkipWhitespace();
};
CharmapReader::CharmapReader(std::string filename) : m_filename(filename)
{
if (filename == "")
{
CharmapReader::CharmapReader(std::string filename) : m_filename(filename) {
if (filename == "") {
m_pos = 0;
m_size = 0;
m_buffer = new char[1] {};
m_buffer = new char[1]{};
return;
}
FILE *fp = std::fopen(filename.c_str(), "rb");
FILE* fp = std::fopen(filename.c_str(), "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str());
@@ -104,45 +94,36 @@ CharmapReader::CharmapReader(std::string filename) : m_filename(filename)
RemoveComments();
}
CharmapReader::~CharmapReader()
{
CharmapReader::~CharmapReader() {
delete[] m_buffer;
}
Lhs CharmapReader::ReadLhs()
{
Lhs CharmapReader::ReadLhs() {
Lhs lhs;
for (;;)
{
for (;;) {
SkipWhitespace();
if (m_buffer[m_pos] == '\n')
{
if (m_buffer[m_pos] == '\n') {
m_pos++;
m_lineNum++;
}
else
{
} else {
break;
}
}
if (m_buffer[m_pos] == '\'')
{
if (m_buffer[m_pos] == '\'') {
m_pos++;
bool isEscape = (m_buffer[m_pos] == '\\');
if (isEscape)
{
if (isEscape) {
m_pos++;
}
unsigned char c = m_buffer[m_pos];
if (c == 0)
{
if (c == 0) {
if (m_pos >= m_size)
RaiseError("unexpected EOF in UTF-8 character literal");
else
@@ -167,58 +148,45 @@ Lhs CharmapReader::ReadLhs()
lhs.code = code;
if (isEscape)
{
if (isEscape) {
if (code >= 128)
RaiseError("escapes using non-ASCII characters are invalid");
switch (code)
{
case '\'':
lhs.type = LhsType::Char;
break;
case '\\':
lhs.type = LhsType::Char;
case '"':
RaiseError("cannot escape double quote");
break;
default:
lhs.type = LhsType::Escape;
switch (code) {
case '\'':
lhs.type = LhsType::Char;
break;
case '\\':
lhs.type = LhsType::Char;
case '"':
RaiseError("cannot escape double quote");
break;
default:
lhs.type = LhsType::Escape;
}
}
else
{
} else {
if (code == '\'')
RaiseError("empty character literal");
lhs.type = LhsType::Char;
}
}
else if (IsIdentifierStartingChar(m_buffer[m_pos]))
{
} else if (IsIdentifierStartingChar(m_buffer[m_pos])) {
lhs.type = LhsType::Constant;
lhs.name = ReadConstant();
}
else if (m_buffer[m_pos] == '\r')
{
} else if (m_buffer[m_pos] == '\r') {
RaiseError("only Unix-style LF newlines are supported");
}
else if (m_buffer[m_pos] == 0)
{
} else if (m_buffer[m_pos] == 0) {
if (m_pos < m_size)
RaiseError("unexpected null character");
lhs.type = LhsType::None;
}
else
{
} else {
RaiseError("junk at start of line");
}
return lhs;
}
void CharmapReader::ExpectEqualsSign()
{
void CharmapReader::ExpectEqualsSign() {
SkipWhitespace();
if (m_buffer[m_pos] != '=')
@@ -227,8 +195,7 @@ void CharmapReader::ExpectEqualsSign()
m_pos++;
}
static unsigned int ConvertHexDigit(char c)
{
static unsigned int ConvertHexDigit(char c) {
unsigned int digit = 0;
if (c >= '0' && c <= '9')
@@ -241,16 +208,14 @@ static unsigned int ConvertHexDigit(char c)
return digit;
}
std::string CharmapReader::ReadSequence()
{
std::string CharmapReader::ReadSequence() {
SkipWhitespace();
long startPos = m_pos;
unsigned int length = 0;
while (IsAsciiHexDigit(m_buffer[m_pos]) && IsAsciiHexDigit(m_buffer[m_pos + 1]))
{
while (IsAsciiHexDigit(m_buffer[m_pos]) && IsAsciiHexDigit(m_buffer[m_pos + 1])) {
m_pos += 2;
length++;
@@ -271,8 +236,7 @@ std::string CharmapReader::ReadSequence()
m_pos = startPos;
for (unsigned int i = 0; i < length; i++)
{
for (unsigned int i = 0; i < length; i++) {
unsigned int digit1 = ConvertHexDigit(m_buffer[m_pos]);
unsigned int digit2 = ConvertHexDigit(m_buffer[m_pos + 1]);
unsigned char byte = digit1 * 16 + digit2;
@@ -285,32 +249,23 @@ std::string CharmapReader::ReadSequence()
return sequence;
}
void CharmapReader::ExpectEmptyRestOfLine()
{
void CharmapReader::ExpectEmptyRestOfLine() {
SkipWhitespace();
if (m_buffer[m_pos] == 0)
{
if (m_buffer[m_pos] == 0) {
if (m_pos < m_size)
RaiseError("unexpected null character");
}
else if (m_buffer[m_pos] == '\n')
{
} else if (m_buffer[m_pos] == '\n') {
m_pos++;
m_lineNum++;
}
else if (m_buffer[m_pos] == '\r')
{
} else if (m_buffer[m_pos] == '\r') {
RaiseError("only Unix-style LF newlines are supported");
}
else
{
} else {
RaiseError("junk at end of line");
}
}
void CharmapReader::RaiseError(const char* format, ...)
{
void CharmapReader::RaiseError(const char* format, ...) {
const int bufferSize = 1024;
char buffer[bufferSize];
@@ -324,36 +279,26 @@ void CharmapReader::RaiseError(const char* format, ...)
std::exit(1);
}
void CharmapReader::RemoveComments()
{
void CharmapReader::RemoveComments() {
long pos = 0;
bool inString = false;
for (;;)
{
for (;;) {
if (m_buffer[pos] == 0)
return;
if (inString)
{
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == '\'')
{
if (inString) {
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == '\'') {
pos += 2;
}
else
{
} else {
if (m_buffer[pos] == '\'')
inString = false;
pos++;
}
}
else if (m_buffer[pos] == '@')
{
} else if (m_buffer[pos] == '@') {
while (m_buffer[pos] != '\n' && m_buffer[pos] != 0)
m_buffer[pos++] = ' ';
}
else
{
} else {
if (m_buffer[pos] == '\'')
inString = true;
pos++;
@@ -361,8 +306,7 @@ void CharmapReader::RemoveComments()
}
}
std::string CharmapReader::ReadConstant()
{
std::string CharmapReader::ReadConstant() {
long startPos = m_pos;
while (IsIdentifierChar(m_buffer[m_pos]))
@@ -371,18 +315,15 @@ std::string CharmapReader::ReadConstant()
return std::string(&m_buffer[startPos], m_pos - startPos);
}
void CharmapReader::SkipWhitespace()
{
void CharmapReader::SkipWhitespace() {
while (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
m_pos++;
}
Charmap::Charmap(std::string filename)
{
Charmap::Charmap(std::string filename) {
CharmapReader reader(filename);
for (;;)
{
for (;;) {
Lhs lhs = reader.ReadLhs();
if (lhs.type == LhsType::None)
@@ -392,23 +333,22 @@ Charmap::Charmap(std::string filename)
std::string sequence = reader.ReadSequence();
switch (lhs.type)
{
case LhsType::Char:
if (m_chars.find(lhs.code) != m_chars.end())
reader.RaiseError("redefining char");
m_chars[lhs.code] = sequence;
break;
case LhsType::Escape:
if (m_escapes[lhs.code].length() != 0)
reader.RaiseError("redefining escape");
m_escapes[lhs.code] = sequence;
break;
case LhsType::Constant:
if (m_constants.find(lhs.name) != m_constants.end())
reader.RaiseError("redefining constant");
m_constants[lhs.name] = sequence;
break;
switch (lhs.type) {
case LhsType::Char:
if (m_chars.find(lhs.code) != m_chars.end())
reader.RaiseError("redefining char");
m_chars[lhs.code] = sequence;
break;
case LhsType::Escape:
if (m_escapes[lhs.code].length() != 0)
reader.RaiseError("redefining escape");
m_escapes[lhs.code] = sequence;
break;
case LhsType::Constant:
if (m_constants.find(lhs.name) != m_constants.end())
reader.RaiseError("redefining constant");
m_constants[lhs.name] = sequence;
break;
}
reader.ExpectEmptyRestOfLine();
Executable → Regular
+7 -10
View File
@@ -26,13 +26,11 @@
#include <map>
#include <vector>
class Charmap
{
public:
class Charmap {
public:
Charmap(std::string filename);
std::string Char(std::int32_t code)
{
std::string Char(std::int32_t code) {
auto it = m_chars.find(code);
if (it == m_chars.end())
@@ -41,13 +39,11 @@ public:
return it->second;
}
std::string Escape(unsigned char code)
{
std::string Escape(unsigned char code) {
return m_escapes[code];
}
std::string Constant(std::string identifier)
{
std::string Constant(std::string identifier) {
auto it = m_constants.find(identifier);
if (it == m_constants.end())
@@ -55,7 +51,8 @@ public:
return it->second;
}
private:
private:
std::map<std::int32_t, std::string> m_chars;
std::string m_escapes[128];
std::map<std::string, std::string> m_constants;
Executable → Regular
+36 -53
View File
@@ -28,13 +28,10 @@
Charmap* g_charmap;
std::string g_buildName;
void PrintAsmBytes(unsigned char *s, int length)
{
if (length > 0)
{
void PrintAsmBytes(unsigned char* s, int length) {
if (length > 0) {
std::printf("\t.byte ");
for (int i = 0; i < length; i++)
{
for (int i = 0; i < length; i++) {
std::printf("0x%02X", s[i]);
if (i < length - 1)
@@ -44,16 +41,13 @@ void PrintAsmBytes(unsigned char *s, int length)
}
}
void PreprocAsmFile(std::string filename)
{
void PreprocAsmFile(std::string filename) {
std::stack<AsmFile> stack;
stack.push(AsmFile(filename));
for (;;)
{
while (stack.top().IsAtEnd())
{
for (;;) {
while (stack.top().IsAtEnd()) {
stack.pop();
if (stack.empty())
@@ -64,54 +58,45 @@ void PreprocAsmFile(std::string filename)
Directive directive = stack.top().GetDirective();
switch (directive)
{
case Directive::Include:
stack.push(AsmFile(stack.top().ReadPath()));
stack.top().OutputLocation();
break;
case Directive::String:
{
unsigned char s[kMaxStringLength];
int length = stack.top().ReadString(s);
PrintAsmBytes(s, length);
break;
}
case Directive::Braille:
{
unsigned char s[kMaxStringLength];
int length = stack.top().ReadBraille(s);
PrintAsmBytes(s, length);
break;
}
case Directive::Unknown:
{
std::string globalLabel = stack.top().GetGlobalLabel();
if (globalLabel.length() != 0)
{
const char *s = globalLabel.c_str();
std::printf("%s: ; .global %s\n", s, s);
switch (directive) {
case Directive::Include:
stack.push(AsmFile(stack.top().ReadPath()));
stack.top().OutputLocation();
break;
case Directive::String: {
unsigned char s[kMaxStringLength];
int length = stack.top().ReadString(s);
PrintAsmBytes(s, length);
break;
}
else
{
stack.top().OutputLine();
case Directive::Braille: {
unsigned char s[kMaxStringLength];
int length = stack.top().ReadBraille(s);
PrintAsmBytes(s, length);
break;
}
case Directive::Unknown: {
std::string globalLabel = stack.top().GetGlobalLabel();
break;
}
if (globalLabel.length() != 0) {
const char* s = globalLabel.c_str();
std::printf("%s: ; .global %s\n", s, s);
} else {
stack.top().OutputLine();
}
break;
}
}
}
}
void PreprocCFile(std::string filename)
{
void PreprocCFile(std::string filename) {
CFile cFile(filename);
cFile.Preproc();
}
char* GetFileExtension(char* filename)
{
char* GetFileExtension(char* filename) {
char* extension = filename;
while (*extension != 0)
@@ -131,10 +116,8 @@ char* GetFileExtension(char* filename)
return extension;
}
int main(int argc, char **argv)
{
if (argc != 4 && argc != 3)
{
int main(int argc, char** argv) {
if (argc != 4 && argc != 3) {
std::fprintf(stderr, "Usage: %s BUILD_NAME SRC_FILE CHARMAP_FILE", argv[0]);
return 1;
}
Executable → Regular
+10 -12
View File
@@ -27,21 +27,19 @@
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do \
{ \
std::fprintf(stderr, format, __VA_ARGS__); \
std::exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
std::fprintf(stderr, format, __VA_ARGS__); \
std::exit(1); \
} while (0)
#else
#define FATAL_ERROR(format, ...) \
do \
{ \
std::fprintf(stderr, format, ##__VA_ARGS__); \
std::exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
std::fprintf(stderr, format, ##__VA_ARGS__); \
std::exit(1); \
} while (0)
#endif // _MSC_VER
+62 -103
View File
@@ -27,27 +27,22 @@
#include "utf8.h"
// Reads a charmap char or escape sequence.
std::string StringParser::ReadCharOrEscape()
{
std::string StringParser::ReadCharOrEscape() {
std::string sequence;
bool isEscape = (m_buffer[m_pos] == '\\');
if (isEscape)
{
if (isEscape) {
m_pos++;
if (m_buffer[m_pos] == '"')
{
if (m_buffer[m_pos] == '"') {
sequence = g_charmap->Char('"');
if (sequence.length() == 0)
RaiseError("no mapping exists for double quote");
return sequence;
}
else if (m_buffer[m_pos] == '\\')
{
} else if (m_buffer[m_pos] == '\\') {
sequence = g_charmap->Char('\\');
if (sequence.length() == 0)
@@ -59,8 +54,7 @@ std::string StringParser::ReadCharOrEscape()
unsigned char c = m_buffer[m_pos];
if (c == 0)
{
if (c == 0) {
if (m_pos >= m_size)
RaiseError("unexpected EOF in UTF-8 string");
else
@@ -82,8 +76,7 @@ std::string StringParser::ReadCharOrEscape()
sequence = isEscape ? g_charmap->Escape(code) : g_charmap->Char(code);
if (sequence.length() == 0)
{
if (sequence.length() == 0) {
if (isEscape)
RaiseError("unknown escape '\\%c'", code);
else
@@ -94,18 +87,15 @@ std::string StringParser::ReadCharOrEscape()
}
// Reads a charmap constant, i.e. "{FOO}".
std::string StringParser::ReadBracketedConstants()
{
std::string StringParser::ReadBracketedConstants() {
std::string totalSequence;
m_pos++; // Assume we're on the left curly bracket.
while (m_buffer[m_pos] != '}')
{
while (m_buffer[m_pos] != '}') {
SkipWhitespace();
if (IsIdentifierStartingChar(m_buffer[m_pos]))
{
if (IsIdentifierStartingChar(m_buffer[m_pos])) {
long startPos = m_pos;
m_pos++;
@@ -115,44 +105,36 @@ std::string StringParser::ReadBracketedConstants()
std::string sequence = g_charmap->Constant(std::string(&m_buffer[startPos], m_pos - startPos));
if (sequence.length() == 0)
{
if (sequence.length() == 0) {
m_buffer[m_pos] = 0;
RaiseError("unknown constant '%s'", &m_buffer[startPos]);
}
totalSequence += sequence;
}
else if (IsAsciiDigit(m_buffer[m_pos]))
{
} else if (IsAsciiDigit(m_buffer[m_pos])) {
Integer integer = ReadInteger();
switch (integer.size)
{
case 1:
totalSequence += (unsigned char)integer.value;
break;
case 2:
totalSequence += (unsigned char)integer.value;
totalSequence += (unsigned char)(integer.value >> 8);
break;
case 4:
totalSequence += (unsigned char)integer.value;
totalSequence += (unsigned char)(integer.value >> 8);
totalSequence += (unsigned char)(integer.value >> 16);
totalSequence += (unsigned char)(integer.value >> 24);
break;
switch (integer.size) {
case 1:
totalSequence += (unsigned char)integer.value;
break;
case 2:
totalSequence += (unsigned char)integer.value;
totalSequence += (unsigned char)(integer.value >> 8);
break;
case 4:
totalSequence += (unsigned char)integer.value;
totalSequence += (unsigned char)(integer.value >> 8);
totalSequence += (unsigned char)(integer.value >> 16);
totalSequence += (unsigned char)(integer.value >> 24);
break;
}
}
else if (m_buffer[m_pos] == 0)
{
} else if (m_buffer[m_pos] == 0) {
if (m_pos >= m_size)
RaiseError("unexpected EOF after left curly bracket");
else
RaiseError("unexpected null character within curly brackets");
}
else
{
} else {
if (IsAsciiPrintable(m_buffer[m_pos]))
RaiseError("unexpected character '%c' within curly brackets", m_buffer[m_pos]);
else
@@ -166,8 +148,7 @@ std::string StringParser::ReadBracketedConstants()
}
// Reads a charmap string.
int StringParser::ParseString(long srcPos, unsigned char* dest, int& destLength)
{
int StringParser::ParseString(long srcPos, unsigned char* dest, int& destLength) {
m_pos = srcPos;
if (m_buffer[m_pos] != '"')
@@ -179,12 +160,10 @@ int StringParser::ParseString(long srcPos, unsigned char* dest, int& destLength)
destLength = 0;
while (m_buffer[m_pos] != '"')
{
while (m_buffer[m_pos] != '"') {
std::string sequence = (m_buffer[m_pos] == '{') ? ReadBracketedConstants() : ReadCharOrEscape();
for (const char& c : sequence)
{
for (const char& c : sequence) {
if (destLength == kMaxStringLength)
RaiseError("mapped string longer than %d bytes", kMaxStringLength);
@@ -197,8 +176,7 @@ int StringParser::ParseString(long srcPos, unsigned char* dest, int& destLength)
return m_pos - start;
}
void StringParser::RaiseError(const char* format, ...)
{
void StringParser::RaiseError(const char* format, ...) {
const int bufferSize = 1024;
char buffer[bufferSize];
@@ -211,8 +189,7 @@ void StringParser::RaiseError(const char* format, ...)
}
// Converts digit character to numerical value.
static int ConvertDigit(char c, int radix)
{
static int ConvertDigit(char c, int radix) {
int digit;
if (c >= '0' && c <= '9')
@@ -227,26 +204,22 @@ static int ConvertDigit(char c, int radix)
return (digit < radix) ? digit : -1;
}
void StringParser::SkipRestOfInteger(int radix)
{
void StringParser::SkipRestOfInteger(int radix) {
while (ConvertDigit(m_buffer[m_pos], radix) != -1)
m_pos++;
}
StringParser::Integer StringParser::ReadDecimal()
{
StringParser::Integer StringParser::ReadDecimal() {
const int radix = 10;
std::uint64_t n = 0;
int digit;
std::uint64_t max = UINT32_MAX;
long startPos = m_pos;
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1)
{
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1) {
n = n * radix + digit;
if (n >= max)
{
if (n >= max) {
SkipRestOfInteger(radix);
std::string intLiteral(m_buffer + startPos, m_pos - startPos);
@@ -258,23 +231,17 @@ StringParser::Integer StringParser::ReadDecimal()
int size;
if (m_buffer[m_pos] == 'H')
{
if (n >= 0x10000)
{
if (m_buffer[m_pos] == 'H') {
if (n >= 0x10000) {
RaiseError("%lu is too large to be a halfword", (unsigned long)n);
}
size = 2;
m_pos++;
}
else if (m_buffer[m_pos] == 'W')
{
} else if (m_buffer[m_pos] == 'W') {
size = 4;
m_pos++;
}
else
{
} else {
if (n >= 0x10000)
size = 4;
else if (n >= 0x100)
@@ -283,23 +250,20 @@ StringParser::Integer StringParser::ReadDecimal()
size = 1;
}
return{ static_cast<std::uint32_t>(n), size };
return { static_cast<std::uint32_t>(n), size };
}
StringParser::Integer StringParser::ReadHex()
{
StringParser::Integer StringParser::ReadHex() {
const int radix = 16;
std::uint64_t n = 0;
int digit;
std::uint64_t max = UINT32_MAX;
long startPos = m_pos;
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1)
{
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1) {
n = n * radix + digit;
if (n >= max)
{
if (n >= max) {
SkipRestOfInteger(radix);
std::string intLiteral(m_buffer + startPos, m_pos - startPos);
@@ -312,34 +276,30 @@ StringParser::Integer StringParser::ReadHex()
int length = m_pos - startPos;
int size = 0;
switch (length)
{
case 2:
size = 1;
break;
case 4:
size = 2;
break;
case 8:
size = 4;
break;
default:
{
std::string intLiteral(m_buffer + startPos, m_pos - startPos);
RaiseError("hex integer literal \"0x%s\" doesn't have length of 2, 4, or 8 digits", intLiteral.c_str());
}
switch (length) {
case 2:
size = 1;
break;
case 4:
size = 2;
break;
case 8:
size = 4;
break;
default: {
std::string intLiteral(m_buffer + startPos, m_pos - startPos);
RaiseError("hex integer literal \"0x%s\" doesn't have length of 2, 4, or 8 digits", intLiteral.c_str());
}
}
return{ static_cast<std::uint32_t>(n), size };
return { static_cast<std::uint32_t>(n), size };
}
StringParser::Integer StringParser::ReadInteger()
{
StringParser::Integer StringParser::ReadInteger() {
if (!IsAsciiDigit(m_buffer[m_pos]))
RaiseError("expected integer");
if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x')
{
if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x') {
m_pos += 2;
return ReadHex();
}
@@ -348,8 +308,7 @@ StringParser::Integer StringParser::ReadInteger()
}
// Skips tabs and spaces.
void StringParser::SkipWhitespace()
{
void StringParser::SkipWhitespace() {
while (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
m_pos++;
}
+7 -8
View File
@@ -25,15 +25,14 @@
#include <string>
#include "preproc.h"
class StringParser
{
public:
StringParser(char* buffer, long size) : m_buffer(buffer), m_size(size), m_pos(0) {}
int ParseString(long srcPos, unsigned char* dest, int &destLength);
class StringParser {
public:
StringParser(char* buffer, long size) : m_buffer(buffer), m_size(size), m_pos(0) {
}
int ParseString(long srcPos, unsigned char* dest, int& destLength);
private:
struct Integer
{
private:
struct Integer {
std::uint32_t value;
int size;
};
Executable → Regular
+30 -28
View File
@@ -24,17 +24,23 @@
#include <cstdint>
#include "utf8.h"
static const unsigned char s_byteTypeTable[] =
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
static const unsigned char s_byteTypeTable[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df
0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef
0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff
};
const unsigned char s0 = 0 * 12;
@@ -47,28 +53,25 @@ const unsigned char s6 = 6 * 12;
const unsigned char s7 = 7 * 12;
const unsigned char s8 = 8 * 12;
static const unsigned char s_transitionTable[] =
{
s0,s1,s2,s3,s5,s8,s7,s1,s1,s1,s4,s6, // s0
s1,s1,s1,s1,s1,s1,s1,s1,s1,s1,s1,s1, // s1
s1,s0,s1,s1,s1,s1,s1,s0,s1,s0,s1,s1, // s2
s1,s2,s1,s1,s1,s1,s1,s2,s1,s2,s1,s1, // s3
s1,s1,s1,s1,s1,s1,s1,s2,s1,s1,s1,s1, // s4
s1,s2,s1,s1,s1,s1,s1,s1,s1,s2,s1,s1, // s5
s1,s1,s1,s1,s1,s1,s1,s3,s1,s3,s1,s1, // s6
s1,s3,s1,s1,s1,s1,s1,s3,s1,s3,s1,s1, // s7
s1,s3,s1,s1,s1,s1,s1,s1,s1,s1,s1,s1, // s8
static const unsigned char s_transitionTable[] = {
s0, s1, s2, s3, s5, s8, s7, s1, s1, s1, s4, s6, // s0
s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // s1
s1, s0, s1, s1, s1, s1, s1, s0, s1, s0, s1, s1, // s2
s1, s2, s1, s1, s1, s1, s1, s2, s1, s2, s1, s1, // s3
s1, s1, s1, s1, s1, s1, s1, s2, s1, s1, s1, s1, // s4
s1, s2, s1, s1, s1, s1, s1, s1, s1, s2, s1, s1, // s5
s1, s1, s1, s1, s1, s1, s1, s3, s1, s3, s1, s1, // s6
s1, s3, s1, s1, s1, s1, s1, s3, s1, s3, s1, s1, // s7
s1, s3, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // s8
};
// Decodes UTF-8 encoded Unicode code point at "s".
UnicodeChar DecodeUtf8(const char* s)
{
UnicodeChar DecodeUtf8(const char* s) {
UnicodeChar unicodeChar;
int state = s0;
auto start = s;
do
{
do {
unsigned char byte = *s++;
int type = s_byteTypeTable[byte];
@@ -79,8 +82,7 @@ UnicodeChar DecodeUtf8(const char* s)
state = s_transitionTable[state + type];
if (state == s1)
{
if (state == s1) {
unicodeChar.code = -1;
return unicodeChar;
}
Executable → Regular
+1 -2
View File
@@ -23,8 +23,7 @@
#include <cstdint>
struct UnicodeChar
{
struct UnicodeChar {
std::int32_t code;
int encodingLength;
};
Executable → Regular
+23 -49
View File
@@ -23,11 +23,10 @@
#include "scaninc.h"
#include "asm_file.h"
AsmFile::AsmFile(std::string path)
{
AsmFile::AsmFile(std::string path) {
m_path = path;
FILE *fp = std::fopen(path.c_str(), "rb");
FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path.c_str());
@@ -49,24 +48,20 @@ AsmFile::AsmFile(std::string path)
m_lineNum = 1;
}
AsmFile::~AsmFile()
{
AsmFile::~AsmFile() {
delete[] m_buffer;
}
IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
{
IncDirectiveType AsmFile::ReadUntilIncDirective(std::string& path) {
// At the beginning of each loop iteration, the current file position
// should be at the start of a line or at the end of the file.
for (;;)
{
for (;;) {
SkipTabsAndSpaces();
IncDirectiveType incDirectiveType = IncDirectiveType::None;
char c = PeekChar();
if (c == '.' || c == '#')
{
if (c == '.' || c == '#') {
m_pos++;
if (MatchIncDirective("incbin", path))
@@ -75,29 +70,21 @@ IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
incDirectiveType = IncDirectiveType::Include;
}
for (;;)
{
for (;;) {
int c = GetChar();
if (c == -1)
return incDirectiveType;
if (c == ';')
{
if (c == ';') {
SkipEndOfLineComment();
break;
}
else if (c == '/' && PeekChar() == '*')
{
} else if (c == '/' && PeekChar() == '*') {
m_pos++;
SkipMultiLineComment();
}
else if (c == '"')
{
} else if (c == '"') {
SkipString();
}
else if (c == '\n')
{
} else if (c == '\n') {
break;
}
}
@@ -107,13 +94,11 @@ IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
}
}
std::string AsmFile::ReadPath()
{
std::string AsmFile::ReadPath() {
int length = 0;
int startPos = m_pos;
for (;;)
{
for (;;) {
int c = GetChar();
if (c == '"')
@@ -141,41 +126,31 @@ std::string AsmFile::ReadPath()
return std::string(m_buffer + startPos, length);
}
void AsmFile::SkipEndOfLineComment()
{
void AsmFile::SkipEndOfLineComment() {
int c;
do
{
do {
c = GetChar();
} while (c != -1 && c != '\n');
}
void AsmFile::SkipMultiLineComment()
{
for (;;)
{
void AsmFile::SkipMultiLineComment() {
for (;;) {
int c = GetChar();
if (c == '*')
{
if (PeekChar() == '/')
{
if (c == '*') {
if (PeekChar() == '/') {
m_pos++;
return;
}
}
else if (c == -1)
{
} else if (c == -1) {
return;
}
}
}
void AsmFile::SkipString()
{
for (;;)
{
void AsmFile::SkipString() {
for (;;) {
int c = GetChar();
if (c == '"')
@@ -184,8 +159,7 @@ void AsmFile::SkipString()
if (c == -1)
FATAL_INPUT_ERROR("unexpected EOF in string\n");
if (c == '\\')
{
if (c == '\\') {
c = GetChar();
}
}
Executable → Regular
+12 -26
View File
@@ -24,43 +24,32 @@
#include <string>
#include "scaninc.h"
enum class IncDirectiveType
{
None,
Include,
Incbin
};
enum class IncDirectiveType { None, Include, Incbin };
class AsmFile
{
public:
class AsmFile {
public:
AsmFile(std::string path);
~AsmFile();
IncDirectiveType ReadUntilIncDirective(std::string& path);
private:
char *m_buffer;
private:
char* m_buffer;
int m_pos;
int m_size;
int m_lineNum;
std::string m_path;
int GetChar()
{
int GetChar() {
if (m_pos >= m_size)
return -1;
int c = m_buffer[m_pos++];
if (c == '\r')
{
if (m_pos < m_size && m_buffer[m_pos++] == '\n')
{
if (c == '\r') {
if (m_pos < m_size && m_buffer[m_pos++] == '\n') {
m_lineNum++;
return '\n';
}
else
{
} else {
FATAL_INPUT_ERROR("CR line endings are not supported\n");
}
}
@@ -72,22 +61,19 @@ private:
}
// No newline translation because it's not needed for any use of this function.
int PeekChar()
{
int PeekChar() {
if (m_pos >= m_size)
return -1;
return m_buffer[m_pos];
}
void SkipTabsAndSpaces()
{
void SkipTabsAndSpaces() {
while (m_pos < m_size && (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' '))
m_pos++;
}
bool MatchIncDirective(std::string directiveName, std::string& path)
{
bool MatchIncDirective(std::string directiveName, std::string& path) {
int length = directiveName.length();
int i;
Executable → Regular
+38 -81
View File
@@ -20,11 +20,10 @@
#include "c_file.h"
CFile::CFile(std::string path)
{
CFile::CFile(std::string path) {
m_path = path;
FILE *fp = std::fopen(path.c_str(), "rb");
FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path.c_str());
@@ -47,37 +46,26 @@ CFile::CFile(std::string path)
m_lineNum = 1;
}
CFile::~CFile()
{
CFile::~CFile() {
delete[] m_buffer;
}
void CFile::FindIncbins()
{
void CFile::FindIncbins() {
char stringChar = 0;
while (m_pos < m_size)
{
if (stringChar)
{
if (m_buffer[m_pos] == stringChar)
{
while (m_pos < m_size) {
if (stringChar) {
if (m_buffer[m_pos] == stringChar) {
m_pos++;
stringChar = 0;
}
else if (m_buffer[m_pos] == '\\' && m_buffer[m_pos + 1] == stringChar)
{
} else if (m_buffer[m_pos] == '\\' && m_buffer[m_pos + 1] == stringChar) {
m_pos += 2;
}
else
{
} else {
if (m_buffer[m_pos] == '\n')
m_lineNum++;
m_pos++;
}
}
else
{
} else {
SkipWhitespace();
CheckInclude();
CheckIncbin();
@@ -99,10 +87,8 @@ void CFile::FindIncbins()
}
}
bool CFile::ConsumeHorizontalWhitespace()
{
if (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
{
bool CFile::ConsumeHorizontalWhitespace() {
if (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ') {
m_pos++;
return true;
}
@@ -110,17 +96,14 @@ bool CFile::ConsumeHorizontalWhitespace()
return false;
}
bool CFile::ConsumeNewline()
{
if (m_buffer[m_pos] == '\n')
{
bool CFile::ConsumeNewline() {
if (m_buffer[m_pos] == '\n') {
m_pos++;
m_lineNum++;
return true;
}
if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n')
{
if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n') {
m_pos += 2;
m_lineNum++;
return true;
@@ -129,13 +112,10 @@ bool CFile::ConsumeNewline()
return false;
}
bool CFile::ConsumeComment()
{
if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '*')
{
bool CFile::ConsumeComment() {
if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '*') {
m_pos += 2;
while (m_buffer[m_pos] != '*' || m_buffer[m_pos + 1] != '/')
{
while (m_buffer[m_pos] != '*' || m_buffer[m_pos + 1] != '/') {
if (m_buffer[m_pos] == 0)
return false;
if (!ConsumeNewline())
@@ -143,12 +123,9 @@ bool CFile::ConsumeComment()
}
m_pos += 2;
return true;
}
else if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '/')
{
} else if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '/') {
m_pos += 2;
while (!ConsumeNewline())
{
while (!ConsumeNewline()) {
if (m_buffer[m_pos] == 0)
return false;
m_pos++;
@@ -159,14 +136,12 @@ bool CFile::ConsumeComment()
return false;
}
void CFile::SkipWhitespace()
{
void CFile::SkipWhitespace() {
while (ConsumeHorizontalWhitespace() || ConsumeNewline() || ConsumeComment())
;
}
bool CFile::CheckIdentifier(const std::string& ident)
{
bool CFile::CheckIdentifier(const std::string& ident) {
unsigned int i;
for (i = 0; i < ident.length() && m_pos + i < (unsigned)m_size; i++)
@@ -176,15 +151,13 @@ bool CFile::CheckIdentifier(const std::string& ident)
return (i == ident.length());
}
void CFile::CheckInclude()
{
void CFile::CheckInclude() {
if (m_buffer[m_pos] != '#')
return;
std::string ident = "#include";
if (!CheckIdentifier(ident))
{
if (!CheckIdentifier(ident)) {
return;
}
@@ -199,27 +172,19 @@ void CFile::CheckInclude()
}
}
void CFile::CheckIncbin()
{
void CFile::CheckIncbin() {
// Optimization: assume most lines are not incbins
if (!(m_buffer[m_pos+0] == 'I'
&& m_buffer[m_pos+1] == 'N'
&& m_buffer[m_pos+2] == 'C'
&& m_buffer[m_pos+3] == 'B'
&& m_buffer[m_pos+4] == 'I'
&& m_buffer[m_pos+5] == 'N'
&& m_buffer[m_pos+6] == '_'))
{
return;
if (!(m_buffer[m_pos + 0] == 'I' && m_buffer[m_pos + 1] == 'N' && m_buffer[m_pos + 2] == 'C' &&
m_buffer[m_pos + 3] == 'B' && m_buffer[m_pos + 4] == 'I' && m_buffer[m_pos + 5] == 'N' &&
m_buffer[m_pos + 6] == '_')) {
return;
}
std::string idents[6] = { "INCBIN_S8", "INCBIN_U8", "INCBIN_S16", "INCBIN_U16", "INCBIN_S32", "INCBIN_U32" };
int incbinType = -1;
for (int i = 0; i < 6; i++)
{
if (CheckIdentifier(idents[i]))
{
for (int i = 0; i < 6; i++) {
if (CheckIdentifier(idents[i])) {
incbinType = i;
break;
}
@@ -235,8 +200,7 @@ void CFile::CheckIncbin()
SkipWhitespace();
if (m_buffer[m_pos] != '(')
{
if (m_buffer[m_pos] != '(') {
m_pos = oldPos;
m_lineNum = oldLineNum;
return;
@@ -244,8 +208,7 @@ void CFile::CheckIncbin()
m_pos++;
while (true)
{
while (true) {
SkipWhitespace();
std::string path = ReadPath();
@@ -264,15 +227,11 @@ void CFile::CheckIncbin()
FATAL_INPUT_ERROR("expected ')'");
m_pos++;
}
std::string CFile::ReadPath()
{
if (m_buffer[m_pos] != '"')
{
if (m_buffer[m_pos] == '<')
{
std::string CFile::ReadPath() {
if (m_buffer[m_pos] != '"') {
if (m_buffer[m_pos] == '<') {
return std::string();
}
FATAL_INPUT_ERROR("expected '\"' or '<'");
@@ -282,10 +241,8 @@ std::string CFile::ReadPath()
int startPos = m_pos;
while (m_buffer[m_pos] != '"')
{
if (m_buffer[m_pos] == 0)
{
while (m_buffer[m_pos] != '"') {
if (m_buffer[m_pos] == 0) {
if (m_pos >= m_size)
FATAL_INPUT_ERROR("unexpected EOF in path string");
else
Executable → Regular
+10 -7
View File
@@ -26,17 +26,20 @@
#include <memory>
#include "scaninc.h"
class CFile
{
public:
class CFile {
public:
CFile(std::string path);
~CFile();
void FindIncbins();
const std::set<std::string>& GetIncbins() { return m_incbins; }
const std::set<std::string>& GetIncludes() { return m_includes; }
const std::set<std::string>& GetIncbins() {
return m_incbins;
}
const std::set<std::string>& GetIncludes() {
return m_includes;
}
private:
char *m_buffer;
private:
char* m_buffer;
int m_pos;
int m_size;
int m_lineNum;
Executable → Regular
+18 -35
View File
@@ -27,9 +27,8 @@
#include "scaninc.h"
#include "source_file.h"
bool CanOpenFile(std::string path)
{
FILE *fp = std::fopen(path.c_str(), "rb");
bool CanOpenFile(std::string path) {
FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == NULL)
return false;
@@ -38,10 +37,9 @@ bool CanOpenFile(std::string path)
return true;
}
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] FILE_PATH\n";
const char* const USAGE = "Usage: scaninc [-I INCLUDE_PATH] FILE_PATH\n";
int main(int argc, char **argv)
{
int main(int argc, char** argv) {
std::queue<std::string> filesToProcess;
std::set<std::string> dependencies;
@@ -50,26 +48,20 @@ int main(int argc, char **argv)
argc--;
argv++;
while (argc > 1)
{
while (argc > 1) {
std::string arg(argv[0]);
if (arg.substr(0, 2) == "-I")
{
if (arg.substr(0, 2) == "-I") {
std::string includeDir = arg.substr(2);
if (includeDir.empty())
{
if (includeDir.empty()) {
argc--;
argv++;
includeDir = std::string(argv[0]);
}
if (!includeDir.empty() && includeDir.back() != '/')
{
if (!includeDir.empty() && includeDir.back() != '/') {
includeDir += '/';
}
includeDirs.push_back(includeDir);
}
else
{
} else {
FATAL_ERROR(USAGE);
}
argc--;
@@ -84,36 +76,28 @@ int main(int argc, char **argv)
filesToProcess.push(initialPath);
while (!filesToProcess.empty())
{
while (!filesToProcess.empty()) {
std::string filePath = filesToProcess.front();
SourceFile file(filePath);
filesToProcess.pop();
includeDirs.push_back(file.GetSrcDir());
for (auto incbin : file.GetIncbins())
{
for (auto incbin : file.GetIncbins()) {
// Search for the incbin in the include directories as well.
for (auto includeDir : includeDirs)
{
for (auto includeDir : includeDirs) {
std::string path(includeDir + incbin);
if (CanOpenFile(path))
{
if (CanOpenFile(path)) {
dependencies.insert(path);
break;
}
}
}
for (auto include : file.GetIncludes())
{
for (auto includeDir : includeDirs)
{
for (auto include : file.GetIncludes()) {
for (auto includeDir : includeDirs) {
std::string path(includeDir + include);
if (CanOpenFile(path))
{
if (CanOpenFile(path)) {
bool inserted = dependencies.insert(path).second;
if (inserted)
{
if (inserted) {
filesToProcess.push(path);
}
break;
@@ -123,8 +107,7 @@ int main(int argc, char **argv)
includeDirs.pop_back();
}
for (const std::string &path : dependencies)
{
for (const std::string& path : dependencies) {
std::printf("%s\n", path.c_str());
}
}
Executable → Regular
+20 -20
View File
@@ -26,31 +26,31 @@
#ifdef _MSC_VER
#define FATAL_INPUT_ERROR(format, ...) \
do { \
fprintf(stderr, "%s:%d " format, m_path.c_str(), m_lineNum, __VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_INPUT_ERROR(format, ...) \
do { \
fprintf(stderr, "%s:%d " format, m_path.c_str(), m_lineNum, __VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#else
#define FATAL_INPUT_ERROR(format, ...) \
do { \
fprintf(stderr, "%s:%d " format, m_path.c_str(), m_lineNum, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_INPUT_ERROR(format, ...) \
do { \
fprintf(stderr, "%s:%d " format, m_path.c_str(), m_lineNum, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#endif // _MSC_VER
+15 -32
View File
@@ -21,9 +21,7 @@
#include <new>
#include "source_file.h"
SourceFileType GetFileType(std::string& path)
{
SourceFileType GetFileType(std::string& path) {
std::size_t pos = path.find_last_of('.');
if (pos == std::string::npos)
@@ -41,13 +39,12 @@ SourceFileType GetFileType(std::string& path)
return SourceFileType::Inc;
else
FATAL_ERROR("Unrecognized extension \"%s\"\n", extension.c_str());
// Unreachable
return SourceFileType::Cpp;
}
std::string GetDir(std::string& path)
{
std::string GetDir(std::string& path) {
std::size_t slash = path.rfind('/');
if (slash != std::string::npos)
@@ -56,20 +53,15 @@ std::string GetDir(std::string& path)
return std::string("");
}
SourceFile::SourceFile(std::string path)
{
SourceFile::SourceFile(std::string path) {
m_file_type = GetFileType(path);
m_src_dir = GetDir(path);
if (m_file_type == SourceFileType::Cpp
|| m_file_type == SourceFileType::Header)
{
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header) {
new (&m_source_file.c_file) CFile(path);
m_source_file.c_file.FindIncbins();
}
else
{
} else {
AsmFile file(path);
std::set<std::string> incbins;
std::set<std::string> includes;
@@ -77,49 +69,40 @@ SourceFile::SourceFile(std::string path)
IncDirectiveType incDirectiveType;
std::string outputPath;
while ((incDirectiveType = file.ReadUntilIncDirective(outputPath)) != IncDirectiveType::None)
{
while ((incDirectiveType = file.ReadUntilIncDirective(outputPath)) != IncDirectiveType::None) {
if (incDirectiveType == IncDirectiveType::Include)
includes.insert(outputPath);
else
incbins.insert(outputPath);
}
new (&m_source_file.asm_wrapper) SourceFile::InnerUnion::AsmWrapper{incbins, includes};
new (&m_source_file.asm_wrapper) SourceFile::InnerUnion::AsmWrapper{ incbins, includes };
}
}
SourceFile::~SourceFile()
{
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
{
SourceFile::~SourceFile() {
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header) {
m_source_file.c_file.~CFile();
}
else
{
} else {
m_source_file.asm_wrapper.asm_incbins.~set();
m_source_file.asm_wrapper.asm_includes.~set();
}
}
const std::set<std::string>& SourceFile::GetIncbins()
{
const std::set<std::string>& SourceFile::GetIncbins() {
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
return m_source_file.c_file.GetIncbins();
else
return m_source_file.asm_wrapper.asm_incbins;
}
const std::set<std::string>& SourceFile::GetIncludes()
{
const std::set<std::string>& SourceFile::GetIncludes() {
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
return m_source_file.c_file.GetIncludes();
else
return m_source_file.asm_wrapper.asm_includes;
}
std::string& SourceFile::GetSrcDir()
{
std::string& SourceFile::GetSrcDir() {
return m_src_dir;
}
Executable → Regular
+8 -17
View File
@@ -26,32 +26,24 @@
#include "asm_file.h"
#include "c_file.h"
enum class SourceFileType
{
Cpp,
Header,
Asm,
Inc
};
enum class SourceFileType { Cpp, Header, Asm, Inc };
SourceFileType GetFileType(std::string& path);
class SourceFile
{
public:
class SourceFile {
public:
SourceFile(std::string path);
~SourceFile();
SourceFile(SourceFile const&) = delete;
SourceFile(SourceFile&&) = delete;
SourceFile& operator =(SourceFile const&) = delete;
SourceFile& operator =(SourceFile&&) = delete;
SourceFile& operator=(SourceFile const&) = delete;
SourceFile& operator=(SourceFile&&) = delete;
bool HasIncbins();
const std::set<std::string>& GetIncbins();
const std::set<std::string>& GetIncludes();
std::string& GetSrcDir();
private:
private:
union InnerUnion {
CFile c_file;
struct AsmWrapper {
@@ -60,12 +52,11 @@ private:
} asm_wrapper;
// Construction and destruction handled by SourceFile.
InnerUnion() {};
~InnerUnion() {};
InnerUnion(){};
~InnerUnion(){};
} m_source_file;
SourceFileType m_file_type;
std::string m_src_dir;
};
#endif // SOURCE_FILE_H
+288 -473
View File
@@ -4,522 +4,339 @@
using namespace std::string_literals;
using json = nlohmann::json;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
const u32 RomStartAddress = 0x8000000;
namespace {
struct LanguageTable {
const char *name;
u32 address;
};
struct LanguageTable {
const char* name;
u32 address;
};
enum Color {
Color_White,
Color_Red,
Color_Green,
Color_Blue,
Color_Yellow,
enum Color {
Color_White,
Color_Red,
Color_Green,
Color_Blue,
Color_Yellow,
Color_Count,
};
Color_Count,
};
constexpr const char *const ColorStrings[] = {
"White",
"Red",
"Green",
"Blue",
"Yellow",
};
constexpr const char* const ColorStrings[] = {
"White", "Red", "Green", "Blue", "Yellow",
};
enum Input {
Input_A,
Input_B,
Input_Left,
Input_Right,
Input_DUp,
Input_DDown,
Input_DLeft,
Input_DRight,
Input_Dpad,
Input_Select,
Input_Start,
enum Input {
Input_A,
Input_B,
Input_Left,
Input_Right,
Input_DUp,
Input_DDown,
Input_DLeft,
Input_DRight,
Input_Dpad,
Input_Select,
Input_Start,
Input_Count,
};
Input_Count,
};
constexpr const char *const InputStrings[] = {
"A",
"B",
"Left",
"Right",
"DUp",
"DDown",
"DLeft",
"DRight",
"Dpad",
"Select",
"Start",
};
constexpr const char* const InputStrings[] = {
"A", "B", "Left", "Right", "DUp", "DDown", "DLeft", "DRight", "Dpad", "Select", "Start",
};
const std::map<u8, std::string> CharConvertArray = {
{0x0a, "\n"},
{0x0d, "\r"},
{0x20, " "},
{0x21, "!"},
{0x22, "\""},
{0x23, "#"},
{0x24, "$"},
{0x25, "%"},
{0x26, "&"},
{0x27, "\'"},
{0x28, "("},
{0x29, ")"},
{0x2a, "*"},
{0x2b, "+"},
{0x2c, ","},
{0x2d, "-"},
{0x2e, "."},
{0x2f, "/"},
{0x30, "0"},
{0x31, "1"},
{0x32, "2"},
{0x33, "3"},
{0x34, "4"},
{0x35, "5"},
{0x36, "6"},
{0x37, "7"},
{0x38, "8"},
{0x39, "9"},
{0x3a, ":"},
{0x3b, ";"},
{0x3c, "<"},
{0x3d, "="},
{0x3e, ">"},
{0x3f, "?"},
{0x40, "@"},
{0x41, "A"},
{0x42, "B"},
{0x43, "C"},
{0x44, "D"},
{0x45, "E"},
{0x46, "F"},
{0x47, "G"},
{0x48, "H"},
{0x49, "I"},
{0x4a, "J"},
{0x4b, "K"},
{0x4c, "L"},
{0x4d, "M"},
{0x4e, "N"},
{0x4f, "O"},
{0x50, "P"},
{0x51, "Q"},
{0x52, "R"},
{0x53, "S"},
{0x54, "T"},
{0x55, "U"},
{0x56, "V"},
{0x57, "W"},
{0x58, "X"},
{0x59, "Y"},
{0x5a, "Z"},
{0x5b, "["},
{0x5c, "\'"},
{0x5d, "]"},
{0x5e, "^"},
{0x5f, "_"},
{0x60, "`"},
{0x61, "a"},
{0x62, "b"},
{0x63, "c"},
{0x64, "d"},
{0x65, "e"},
{0x66, "f"},
{0x67, "g"},
{0x68, "h"},
{0x69, "i"},
{0x6a, "j"},
{0x6b, "k"},
{0x6c, "l"},
{0x6d, "m"},
{0x6e, "n"},
{0x6f, "o"},
{0x70, "p"},
{0x71, "q"},
{0x72, "r"},
{0x73, "s"},
{0x74, "t"},
{0x75, "u"},
{0x76, "v"},
{0x77, "w"},
{0x78, "x"},
{0x79, "y"},
{0x7a, "z"},
{0x82, ","},
{0x84, ""},
{0x85, ""},
{0x8A, "Š"},
{0x8B, ""},
{0x8C, "Œ"},
{0x8E, "Ž"},
{0x91, ""},
{0x92, ""},
{0x93, ""},
{0x94, ""},
{0x95, "·"},
{0x99, ""},
{0x9A, "š"},
{0x9B, ""},
{0x9C, "œ"},
{0x9E, "ž"},
{0x9F, "Ÿ"},
{0xA1, "¡"},
{0xA3, ""},
{0xAA, "ª"},
{0xAB, "«"},
{0xB0, "º"},
{0xB4, "'"},
{0xB7, "´"},
{0xBA, "º"},
{0xBB, "»"},
{0xBF, "¿"},
{0xC0, "À"},
{0xC1, "Á"},
{0xC2, "Â"},
{0xC3, "Ã"},
{0xC4, "Ä"},
{0xC5, "Å"},
{0xC6, "Æ"},
{0xC7, "Ç"},
{0xC8, "È"},
{0xC9, "É"},
{0xCA, "Ê"},
{0xCB, "Ë"},
{0xCC, "Ì"},
{0xCD, "Í"},
{0xCE, "Î"},
{0xCF, "Ï"},
{0xD0, "Đ"},
{0xD1, "Ñ"},
{0xD2, "Ò"},
{0xD3, "Ó"},
{0xD4, "Ô"},
{0xD5, "Õ"},
{0xD6, "Ö"},
{0xD7, "×"},
{0xD8, "Ø"},
{0xD9, "Ù"},
{0xDA, "Ú"},
{0xDB, "Û"},
{0xDC, "Ü"},
{0xDD, "Ý"},
{0xDE, "Þ"},
{0xDF, "β"},
{0xE0, "à"},
{0xE1, "á"},
{0xE2, "â"},
{0xE3, "ã"},
{0xE4, "ä"},
{0xE5, "å"},
{0xE6, "æ"},
{0xE7, "ç"},
{0xE8, "è"},
{0xE9, "é"},
{0xEA, "ê"},
{0xEB, "ë"},
{0xEC, "ì"},
{0xED, "í"},
{0xEE, "î"},
{0xEF, "ï"},
{0xF0, "ð"},
{0xF1, "ñ"},
{0xF2, "ò"},
{0xF3, "ó"},
{0xF4, "ô"},
{0xF5, "õ"},
{0xF6, "ö"},
{0xF7, "÷"},
{0xF8, "ø"},
{0xF9, "ù"},
{0xFA, "ú"},
{0xFB, "û"},
{0xFC, "ü"},
{0xFD, "ý"},
{0xFE, "þ"},
{0xFF, "ÿ"},
};
const std::map<u8, std::string> CharConvertArray = {
{ 0x0a, "\n" }, { 0x0d, "\r" }, { 0x20, " " }, { 0x21, "!" }, { 0x22, "\"" }, { 0x23, "#" }, { 0x24, "$" },
{ 0x25, "%" }, { 0x26, "&" }, { 0x27, "\'" }, { 0x28, "(" }, { 0x29, ")" }, { 0x2a, "*" }, { 0x2b, "+" },
{ 0x2c, "," }, { 0x2d, "-" }, { 0x2e, "." }, { 0x2f, "/" }, { 0x30, "0" }, { 0x31, "1" }, { 0x32, "2" },
{ 0x33, "3" }, { 0x34, "4" }, { 0x35, "5" }, { 0x36, "6" }, { 0x37, "7" }, { 0x38, "8" }, { 0x39, "9" },
{ 0x3a, ":" }, { 0x3b, ";" }, { 0x3c, "<" }, { 0x3d, "=" }, { 0x3e, ">" }, { 0x3f, "?" }, { 0x40, "@" },
{ 0x41, "A" }, { 0x42, "B" }, { 0x43, "C" }, { 0x44, "D" }, { 0x45, "E" }, { 0x46, "F" }, { 0x47, "G" },
{ 0x48, "H" }, { 0x49, "I" }, { 0x4a, "J" }, { 0x4b, "K" }, { 0x4c, "L" }, { 0x4d, "M" }, { 0x4e, "N" },
{ 0x4f, "O" }, { 0x50, "P" }, { 0x51, "Q" }, { 0x52, "R" }, { 0x53, "S" }, { 0x54, "T" }, { 0x55, "U" },
{ 0x56, "V" }, { 0x57, "W" }, { 0x58, "X" }, { 0x59, "Y" }, { 0x5a, "Z" }, { 0x5b, "[" }, { 0x5c, "\'" },
{ 0x5d, "]" }, { 0x5e, "^" }, { 0x5f, "_" }, { 0x60, "`" }, { 0x61, "a" }, { 0x62, "b" }, { 0x63, "c" },
{ 0x64, "d" }, { 0x65, "e" }, { 0x66, "f" }, { 0x67, "g" }, { 0x68, "h" }, { 0x69, "i" }, { 0x6a, "j" },
{ 0x6b, "k" }, { 0x6c, "l" }, { 0x6d, "m" }, { 0x6e, "n" }, { 0x6f, "o" }, { 0x70, "p" }, { 0x71, "q" },
{ 0x72, "r" }, { 0x73, "s" }, { 0x74, "t" }, { 0x75, "u" }, { 0x76, "v" }, { 0x77, "w" }, { 0x78, "x" },
{ 0x79, "y" }, { 0x7a, "z" }, { 0x82, "," }, { 0x84, "" }, { 0x85, "" }, { 0x8A, "Š" }, { 0x8B, "" },
{ 0x8C, "Œ" }, { 0x8E, "Ž" }, { 0x91, "" }, { 0x92, "" }, { 0x93, "" }, { 0x94, "" }, { 0x95, "·" },
{ 0x99, "" }, { 0x9A, "š" }, { 0x9B, "" }, { 0x9C, "œ" }, { 0x9E, "ž" }, { 0x9F, "Ÿ" }, { 0xA1, "¡" },
{ 0xA3, "" }, { 0xAA, "ª" }, { 0xAB, "«" }, { 0xB0, "º" }, { 0xB4, "'" }, { 0xB7, "´" }, { 0xBA, "º" },
{ 0xBB, "»" }, { 0xBF, "¿" }, { 0xC0, "À" }, { 0xC1, "Á" }, { 0xC2, "Â" }, { 0xC3, "Ã" }, { 0xC4, "Ä" },
{ 0xC5, "Å" }, { 0xC6, "Æ" }, { 0xC7, "Ç" }, { 0xC8, "È" }, { 0xC9, "É" }, { 0xCA, "Ê" }, { 0xCB, "Ë" },
{ 0xCC, "Ì" }, { 0xCD, "Í" }, { 0xCE, "Î" }, { 0xCF, "Ï" }, { 0xD0, "Đ" }, { 0xD1, "Ñ" }, { 0xD2, "Ò" },
{ 0xD3, "Ó" }, { 0xD4, "Ô" }, { 0xD5, "Õ" }, { 0xD6, "Ö" }, { 0xD7, "×" }, { 0xD8, "Ø" }, { 0xD9, "Ù" },
{ 0xDA, "Ú" }, { 0xDB, "Û" }, { 0xDC, "Ü" }, { 0xDD, "Ý" }, { 0xDE, "Þ" }, { 0xDF, "β" }, { 0xE0, "à" },
{ 0xE1, "á" }, { 0xE2, "â" }, { 0xE3, "ã" }, { 0xE4, "ä" }, { 0xE5, "å" }, { 0xE6, "æ" }, { 0xE7, "ç" },
{ 0xE8, "è" }, { 0xE9, "é" }, { 0xEA, "ê" }, { 0xEB, "ë" }, { 0xEC, "ì" }, { 0xED, "í" }, { 0xEE, "î" },
{ 0xEF, "ï" }, { 0xF0, "ð" }, { 0xF1, "ñ" }, { 0xF2, "ò" }, { 0xF3, "ó" }, { 0xF4, "ô" }, { 0xF5, "õ" },
{ 0xF6, "ö" }, { 0xF7, "÷" }, { 0xF8, "ø" }, { 0xF9, "ù" }, { 0xFA, "ú" }, { 0xFB, "û" }, { 0xFC, "ü" },
{ 0xFD, "ý" }, { 0xFE, "þ" }, { 0xFF, "ÿ" },
};
using ConvertFunction = std::string (*const)(const char *&);
using ConvertFunction = std::string (*const)(const char*&);
std::string Unk1Handler(const char *&ptr) {
u8 a = *ptr++;
return fmt::format("{{01:{:02X}}}", a);
}
std::string Unk1Handler(const char*& ptr) {
u8 a = *ptr++;
return fmt::format("{{01:{:02X}}}", a);
}
std::string ColorHandler(const char *&ptr) {
u8 color = *ptr++;
if (color >= Color_Count)
throw std::runtime_error(ptr);
return fmt::format("{{Color:{}}}", ColorStrings[color]);
}
std::string ColorHandler(const char*& ptr) {
u8 color = *ptr++;
if (color >= Color_Count)
throw std::runtime_error(ptr);
return fmt::format("{{Color:{}}}", ColorStrings[color]);
}
std::string SoundHandler(const char *&ptr) {
u8 a = *ptr++;
std::string SoundHandler(const char*& ptr) {
u8 a = *ptr++;
u8 b = *ptr++;
return fmt::format("{{Sound:{:02X}:{:02X}}}", a, b);
}
std::string Unk4Handler(const char*& ptr) {
u8 a = *ptr++;
if (a == 0x10) {
u8 b = *ptr++;
return fmt::format("{{Sound:{:02X}:{:02X}}}", a, b);
return fmt::format("{{04:{:02X}:{:02X}}}", a, b);
} else {
return fmt::format("{{04:{:02X}}}", a);
}
}
std::string Unk4Handler(const char *&ptr) {
u8 a = *ptr++;
if (a == 0x10) {
u8 b = *ptr++;
return fmt::format("{{04:{:02X}:{:02X}}}", a, b);
} else {
return fmt::format("{{04:{:02X}}}", a);
}
std::string ChoiceHandler(const char*& ptr) {
u8 category = *ptr++;
if (category == 0xff) {
return "{Choice:FF}";
} else {
u8 action = *ptr++;
return fmt::format("{{Choice:{:02X}:{:02X}}}", category, action);
}
}
std::string ChoiceHandler(const char *&ptr) {
u8 category = *ptr++;
if (category == 0xff) {
return "{Choice:FF}";
} else {
u8 action = *ptr++;
return fmt::format("{{Choice:{:02X}:{:02X}}}", category, action);
}
std::string VariableHandler(const char*& ptr) {
u8 idx = *ptr++;
if (idx == 0) {
return "{Player}";
} else {
return fmt::format("{{Var:{:X}}}", idx);
}
}
std::string VariableHandler(const char *&ptr) {
u8 idx = *ptr++;
if (idx == 0) {
return "{Player}";
} else {
return fmt::format("{{Var:{:X}}}", idx);
}
}
std::string Unk7Handler(const char*& ptr) {
u8 a = *ptr++;
u8 b = *ptr++;
return fmt::format("{{07:{:02X}:{:02X}}}", a, b);
}
std::string Unk7Handler(const char *&ptr) {
u8 a = *ptr++;
u8 b = *ptr++;
return fmt::format("{{07:{:02X}:{:02X}}}", a, b);
}
std::string Unk8Handler(const char*& ptr) {
u8 a = *ptr++;
if (a != 0xff)
throw std::runtime_error("unmatched unk8: "s + std::to_string(a));
return "{08:FF}";
}
std::string Unk8Handler(const char *&ptr) {
u8 a = *ptr++;
if (a != 0xff)
throw std::runtime_error("unmatched unk8: "s + std::to_string(a));
return "{08:FF}";
}
std::string Unk9Handler(const char*& ptr) {
u8 a = *ptr++;
if (a != 0x78 && a != 0x00)
throw std::runtime_error("unmatched unk8: "s + std::to_string(a));
return fmt::format("{{09:{:02X}}}", a);
}
std::string Unk9Handler(const char *&ptr) {
u8 a = *ptr++;
if (a != 0x78 && a != 0x00)
throw std::runtime_error("unmatched unk8: "s + std::to_string(a));
return fmt::format("{{09:{:02X}}}", a);
}
std::string InputHandler(const char*& ptr) {
u8 key = *ptr++;
if (key > 8)
throw std::runtime_error("unmatched key: "s + std::to_string(key));
return fmt::format("{{Key:{}}}", InputStrings[key]);
}
std::string InputHandler(const char *&ptr) {
u8 key = *ptr++;
if (key > 8)
throw std::runtime_error("unmatched key: "s + std::to_string(key));
return fmt::format("{{Key:{}}}", InputStrings[key]);
}
std::string SymbolHandler(const char*& ptr) {
u8 a = *ptr++;
return fmt::format("{{Symbol:{:02X}}}", a);
}
std::string SymbolHandler(const char *&ptr) {
u8 a = *ptr++;
return fmt::format("{{Symbol:{:02X}}}", a);
}
const std::map<u8, ConvertFunction> FuncConvertArray = {
{ 0x01, Unk1Handler }, { 0x02, ColorHandler }, { 0x03, SoundHandler }, { 0x04, Unk4Handler },
{ 0x05, ChoiceHandler }, { 0x06, VariableHandler }, { 0x07, Unk7Handler }, { 0x08, Unk8Handler },
{ 0x09, Unk9Handler }, { 0x0c, InputHandler }, { 0x0f, SymbolHandler },
};
const std::map<u8, ConvertFunction> FuncConvertArray = {
{0x01, Unk1Handler},
{0x02, ColorHandler},
{0x03, SoundHandler},
{0x04, Unk4Handler},
{0x05, ChoiceHandler},
{0x06, VariableHandler},
{0x07, Unk7Handler},
{0x08, Unk8Handler},
{0x09, Unk9Handler},
{0x0c, InputHandler},
{0x0f, SymbolHandler},
};
std::string ParseTMCString(const char* ptr) {
std::string ret;
std::string ParseTMCString(const char *ptr) {
std::string ret;
while (*ptr) {
u8 c = *ptr++;
while (*ptr) {
u8 c = *ptr++;
/* Convert character. */
{
const auto it = CharConvertArray.find(c);
/* Convert character. */
{
const auto it = CharConvertArray.find(c);
if (it != std::end(CharConvertArray)) {
ret += it->second;
continue;
}
}
/* Convert function. */
{
const auto it = FuncConvertArray.find(c);
if (it != std::end(FuncConvertArray)) {
ret += it->second(ptr);
continue;
}
}
throw std::runtime_error(fmt::format("Unknown characters: {}", ptr));
}
return ret;
}
using RevertFunction = void (*)(const char *&, char *&);
void ColorRevert(const char *&src, char *&dst) {
*dst++ = 0x02;
src++; // ':'
for (u32 i = 0; i < Color_Count; i++) {
const char *const color = ColorStrings[i];
const std::size_t color_len = std::strlen(color);
if (std::strncmp(src, color, color_len) == 0) {
*dst++ = i;
src += color_len;
return;
if (it != std::end(CharConvertArray)) {
ret += it->second;
continue;
}
}
throw std::runtime_error(fmt::format("Color not found: {}", src));
/* Convert function. */
{
const auto it = FuncConvertArray.find(c);
if (it != std::end(FuncConvertArray)) {
ret += it->second(ptr);
continue;
}
}
throw std::runtime_error(fmt::format("Unknown characters: {}", ptr));
}
void SoundRevert(const char *&src, char *&dst) {
*dst++ = 0x03;
*dst++ = std::strtoul(++src, nullptr, 0x10);
src += 2;
*dst++ = std::strtoul(++src, nullptr, 0x10);
src += 2;
}
return ret;
}
void ChoiceRevert(const char *&src, char *&dst) {
*dst++ = 0x05;
u8 choice = std::strtoul(++src, nullptr, 0x10);
using RevertFunction = void (*)(const char*&, char*&);
*dst++ = choice;
src += 2;
if (choice == 0xff)
void ColorRevert(const char*& src, char*& dst) {
*dst++ = 0x02;
src++; // ':'
for (u32 i = 0; i < Color_Count; i++) {
const char* const color = ColorStrings[i];
const std::size_t color_len = std::strlen(color);
if (std::strncmp(src, color, color_len) == 0) {
*dst++ = i;
src += color_len;
return;
*dst++ = std::strtoul(++src, nullptr, 0x10);
src += 2;
}
void PlayerRevert(const char *&src, char *&dst) {
*dst++ = 0x06;
*dst++ = 0x00;
(void)src;
}
void VariableRevert(const char *&src, char *&dst) {
*dst++ = 0x06;
src++; // ':'
*dst++ = std::strtoul(src, nullptr, 0x10);
src++;
}
void KeyRevert(const char *&src, char *&dst) {
*dst++ = 0x0c;
src++; // ':'
for (u32 i = 0; i < Input_Count; i++) {
const char *const input = InputStrings[i];
const std::size_t input_len = std::strlen(input);
if (std::strncmp(src, input, input_len) == 0) {
*dst++ = i;
src += input_len;
return;
}
}
throw std::runtime_error(fmt::format("Input not found: {}", src));
}
void SymbolRevert(const char *&src, char *&dst) {
*dst++ = 0x0f;
src++; // ':'
throw std::runtime_error(fmt::format("Color not found: {}", src));
}
*dst++ = std::strtoul(src, nullptr, 0x10);
src += 2;
void SoundRevert(const char*& src, char*& dst) {
*dst++ = 0x03;
*dst++ = std::strtoul(++src, nullptr, 0x10);
src += 2;
*dst++ = std::strtoul(++src, nullptr, 0x10);
src += 2;
}
void ChoiceRevert(const char*& src, char*& dst) {
*dst++ = 0x05;
u8 choice = std::strtoul(++src, nullptr, 0x10);
*dst++ = choice;
src += 2;
if (choice == 0xff)
return;
*dst++ = std::strtoul(++src, nullptr, 0x10);
src += 2;
}
void PlayerRevert(const char*& src, char*& dst) {
*dst++ = 0x06;
*dst++ = 0x00;
(void)src;
}
void VariableRevert(const char*& src, char*& dst) {
*dst++ = 0x06;
src++; // ':'
*dst++ = std::strtoul(src, nullptr, 0x10);
src++;
}
void KeyRevert(const char*& src, char*& dst) {
*dst++ = 0x0c;
src++; // ':'
for (u32 i = 0; i < Input_Count; i++) {
const char* const input = InputStrings[i];
const std::size_t input_len = std::strlen(input);
if (std::strncmp(src, input, input_len) == 0) {
*dst++ = i;
src += input_len;
return;
}
}
const std::pair<std::string, RevertFunction> FuncRevertArray[] = {
{"Color", ColorRevert},
{"Sound", SoundRevert},
{"Choice", ChoiceRevert},
{"Player", PlayerRevert},
{"Var", VariableRevert},
{"Key", KeyRevert},
{"Symbol", SymbolRevert},
};
throw std::runtime_error(fmt::format("Input not found: {}", src));
}
void WriteTMCString(char *&dst, const std::string &src) {
const char *ptr = src.data();
void SymbolRevert(const char*& src, char*& dst) {
*dst++ = 0x0f;
src++; // ':'
while (*ptr) {
/* Parse special */
{
if (*ptr == '{') {
ptr++;
const auto it = std::find_if(std::begin(FuncRevertArray), std::end(FuncRevertArray), [&](const auto &data) {
*dst++ = std::strtoul(src, nullptr, 0x10);
src += 2;
}
const std::pair<std::string, RevertFunction> FuncRevertArray[] = {
{ "Color", ColorRevert }, { "Sound", SoundRevert }, { "Choice", ChoiceRevert }, { "Player", PlayerRevert },
{ "Var", VariableRevert }, { "Key", KeyRevert }, { "Symbol", SymbolRevert },
};
void WriteTMCString(char*& dst, const std::string& src) {
const char* ptr = src.data();
while (*ptr) {
/* Parse special */
{
if (*ptr == '{') {
ptr++;
const auto it =
std::find_if(std::begin(FuncRevertArray), std::end(FuncRevertArray), [&](const auto& data) {
return std::strncmp(ptr, data.first.c_str(), data.first.size()) == 0;
});
if (it != std::end(FuncRevertArray)) {
ptr += it->first.size();
it->second(ptr, dst);
} else {
do {
*dst++ = std::strtoul(ptr, nullptr, 0x10);
ptr += 2;
} while (*ptr == ':' && (ptr++, true));
}
if (*ptr != '}')
throw std::runtime_error(fmt::format("unmatched characters: \"{}\"\n", ptr));
ptr++;
continue;
if (it != std::end(FuncRevertArray)) {
ptr += it->first.size();
it->second(ptr, dst);
} else {
do {
*dst++ = std::strtoul(ptr, nullptr, 0x10);
ptr += 2;
} while (*ptr == ':' && (ptr++, true));
}
}
/* Convert character. */
{
const auto it = std::find_if(std::begin(CharConvertArray), std::end(CharConvertArray), [ptr](const auto &data) {
if (*ptr != '}')
throw std::runtime_error(fmt::format("unmatched characters: \"{}\"\n", ptr));
ptr++;
continue;
}
}
/* Convert character. */
{
const auto it =
std::find_if(std::begin(CharConvertArray), std::end(CharConvertArray), [ptr](const auto& data) {
return std::strncmp(ptr, data.second.c_str(), data.second.length()) == 0;
});
if (it != std::end(CharConvertArray)) {
ptr += it->second.size();
*dst++ = it->first;
continue;
}
if (it != std::end(CharConvertArray)) {
ptr += it->second.size();
*dst++ = it->first;
continue;
}
throw std::runtime_error(fmt::format("unmatched characters: \"{}\"\n", ptr));
}
*dst++ = '\0';
}
throw std::runtime_error(fmt::format("unmatched characters: \"{}\"\n", ptr));
}
*dst++ = '\0';
}
void ExtractStringTable(std::string &rom_path, const std::vector<LanguageTable> &tables) {
} // namespace
void ExtractStringTable(std::string& rom_path, const std::vector<LanguageTable>& tables) {
const std::vector<char> rom = [&]() {
std::vector<char> rom;
@@ -543,11 +360,9 @@ void ExtractStringTable(std::string &rom_path, const std::vector<LanguageTable>
return rom;
}();
auto ReadAbsolute = [&](u32 address) -> u32 {
return *(u32 *)&rom[address - RomStartAddress];
};
auto ReadAbsolute = [&](u32 address) -> u32 { return *(u32*)&rom[address - RomStartAddress]; };
for (auto &language : tables) {
for (auto& language : tables) {
/* Get category table start. */
const std::size_t table_start = language.address;
@@ -560,7 +375,7 @@ void ExtractStringTable(std::string &rom_path, const std::vector<LanguageTable>
json j = json::array();
for (auto &category_offset : category_table) {
for (auto& category_offset : category_table) {
/* Get string table start. */
const std::size_t category_start = table_start + category_offset;
@@ -571,7 +386,7 @@ void ExtractStringTable(std::string &rom_path, const std::vector<LanguageTable>
std::vector<u32> string_table(string_count);
std::memcpy(&string_table[0], &rom[category_start - RomStartAddress], string_count * sizeof(u32));
auto &category = j.emplace_back();
auto& category = j.emplace_back();
for (std::size_t l = 0; l < string_count; l++) {
/* Get string start. */
@@ -588,7 +403,7 @@ void ExtractStringTable(std::string &rom_path, const std::vector<LanguageTable>
}
}
void PackStringTable(const std::string &src_path, const std::string &dst_path, const std::size_t out_size) {
void PackStringTable(const std::string& src_path, const std::string& dst_path, const std::size_t out_size) {
const json j = [&]() -> json {
std::ifstream ifs(src_path);
@@ -603,16 +418,16 @@ void PackStringTable(const std::string &src_path, const std::string &dst_path, c
std::vector<char> buffer(0x100000);
std::uintptr_t root_start = (std::uintptr_t)buffer.data();
char *root_ptr = buffer.data();
char *table = buffer.data() + j.size() * sizeof(u32);
char* root_ptr = buffer.data();
char* table = buffer.data() + j.size() * sizeof(u32);
for (auto &category : j) {
char *table_ptr = table;
char *str_start = table_ptr + category.size() * sizeof(u32);
char *str_ptr = str_start;
for (auto &str_j : category) {
for (auto& category : j) {
char* table_ptr = table;
char* str_start = table_ptr + category.size() * sizeof(u32);
char* str_ptr = str_start;
for (auto& str_j : category) {
/* Write string offset to table. */
*(u32 *)table_ptr = (std::uintptr_t)str_ptr - (std::uintptr_t)table;
*(u32*)table_ptr = (std::uintptr_t)str_ptr - (std::uintptr_t)table;
table_ptr += sizeof(u32);
auto str = str_j.get<std::string>();
@@ -628,7 +443,7 @@ void PackStringTable(const std::string &src_path, const std::string &dst_path, c
}
/* Write category offset to root table. */
*(u32 *)root_ptr = (std::uintptr_t)table - root_start;
*(u32*)root_ptr = (std::uintptr_t)table - root_start;
root_ptr += sizeof(u32);
table = str_ptr;
@@ -675,7 +490,7 @@ const std::vector<LanguageTable> LanguageTableEU = {
#include <getopt.h>
const char *progname;
const char* progname;
void usage() {
fmt::print(stderr,
@@ -705,7 +520,7 @@ constexpr const struct option long_options[] = {
};
// clang-format on
int main(int argc, char **argv) {
int main(int argc, char** argv) {
std::string src_path;
std::string dst_path;
std::size_t max_size = 0;