mirror of
https://github.com/zeldaret/tmc
synced 2026-08-09 18:58:28 -04:00
apply clang-format to tool sources
This commit is contained in:
Executable → Regular
+85
-93
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
Executable → Regular
+119
-103
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -6,7 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
struct GbaToPngOptions {
|
||||
char *paletteFilePath;
|
||||
char* paletteFilePath;
|
||||
int bitDepth;
|
||||
bool hasTransparency;
|
||||
int width;
|
||||
|
||||
Executable → Regular
+17
-32
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
Executable → Regular
+62
-103
@@ -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++;
|
||||
}
|
||||
|
||||
Executable → Regular
+7
-8
@@ -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
@@ -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
@@ -23,8 +23,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct UnicodeChar
|
||||
{
|
||||
struct UnicodeChar {
|
||||
std::int32_t code;
|
||||
int encodingLength;
|
||||
};
|
||||
|
||||
Executable → Regular
+23
-49
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
Executable → Regular
+15
-32
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user