summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/gbagfx/lz.c30
-rw-r--r--tools/gbagfx/main.c39
-rw-r--r--tools/gbagfx/util.c26
-rw-r--r--tools/gbagfx/util.h1
4 files changed, 83 insertions, 13 deletions
diff --git a/tools/gbagfx/lz.c b/tools/gbagfx/lz.c
index 7669dab9a..c2ba3e327 100644
--- a/tools/gbagfx/lz.c
+++ b/tools/gbagfx/lz.c
@@ -8,28 +8,28 @@
unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSize)
{
if (srcSize < 4)
- return NULL;
+ goto fail;
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
unsigned char *dest = malloc(destSize);
if (dest == NULL)
- return NULL;
+ goto fail;
int srcPos = 4;
int destPos = 0;
for (;;) {
if (srcPos >= srcSize)
- return NULL;
+ goto fail;
unsigned char flags = src[srcPos++];
for (int i = 0; i < 8; i++) {
if (flags & 0x80) {
if (srcPos + 1 >= srcSize)
- return NULL;
+ goto fail;
int blockSize = (src[srcPos] >> 4) + 3;
int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1;
@@ -38,14 +38,20 @@ unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSi
int blockPos = destPos - blockDistance;
- if (destPos + blockSize > destSize || blockPos < 0)
- return NULL;
+ // Some Ruby/Sapphire tilesets overflow.
+ if (destPos + blockSize > destSize) {
+ blockSize = destSize - destPos;
+ fprintf(stderr, "Destination buffer overflow.\n");
+ }
+
+ if (blockPos < 0)
+ goto fail;
for (int j = 0; j < blockSize; j++)
dest[destPos++] = dest[blockPos + j];
} else {
if (srcPos >= srcSize || destPos >= destSize)
- return NULL;
+ goto fail;
dest[destPos++] = src[srcPos++];
}
@@ -58,6 +64,9 @@ unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSi
flags <<= 1;
}
}
+
+fail:
+ FATAL_ERROR("Fatal error while decompressing LZ file.\n");
}
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize)
@@ -65,7 +74,7 @@ unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize)
const int minDistance = 2; // for compatibility with LZ77UnCompVram()
if (srcSize <= 0)
- return NULL;
+ goto fail;
int worstCaseDestSize = 4 + srcSize + ((srcSize + 7) / 8);
@@ -75,7 +84,7 @@ unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize)
unsigned char *dest = malloc(worstCaseDestSize);
if (dest == NULL)
- return NULL;
+ goto fail;
// header
dest[0] = 0x10; // LZ compression type
@@ -140,4 +149,7 @@ unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize)
}
}
}
+
+fail:
+ FATAL_ERROR("Fatal error while compressing LZ file.\n");
}
diff --git a/tools/gbagfx/main.c b/tools/gbagfx/main.c
index 065967a11..e33e061b2 100644
--- a/tools/gbagfx/main.c
+++ b/tools/gbagfx/main.c
@@ -228,13 +228,44 @@ void HandlePngToFullwidthJapaneseFontCommand(char *inputPath, char *outputPath,
FreeImage(&image);
}
-void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
+void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc, char **argv)
{
+ int overflowSize = 0;
+
+ for (int i = 3; i < argc; i++) {
+ char *option = argv[i];
+
+ if (strcmp(option, "-overflow") == 0) {
+ if (i + 1 >= argc)
+ FATAL_ERROR("No size following \"-overflow\".\n");
+
+ i++;
+
+ if (!ParseNumber(argv[i], NULL, 10, &overflowSize))
+ FATAL_ERROR("Failed to parse overflow size.\n");
+
+ if (overflowSize < 1)
+ FATAL_ERROR("Overflow size must be positive.\n");
+ } else {
+ FATAL_ERROR("Unrecognized option \"%s\".\n", option);
+ }
+ }
+
+ // The overflow option allows a quirk in some of Ruby/Sapphire's tilesets
+ // to be reproduced. It works by appending a number of zeros to the data
+ // before compressing it and then amending the LZ header's size field to
+ // reflect the expected size. This will cause an overflow when decompressing
+ // the data.
+
int fileSize;
- unsigned char *buffer = ReadWholeFile(inputPath, &fileSize);
+ unsigned char *buffer = ReadWholeFileZeroPadded(inputPath, &fileSize, overflowSize);
int compressedSize;
- unsigned char *compressedData = LZCompress(buffer, fileSize, &compressedSize);
+ unsigned char *compressedData = LZCompress(buffer, fileSize + overflowSize, &compressedSize);
+
+ compressedData[1] = (unsigned char)fileSize;
+ compressedData[2] = (unsigned char)(fileSize >> 8);
+ compressedData[3] = (unsigned char)(fileSize >> 16);
free(buffer);
@@ -297,7 +328,7 @@ int main(int argc, char **argv)
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].outputFileExtension == NULL || strcmp(handlers[i].outputFileExtension, outputFileExtension) == 0)) {
handlers[i].function(inputPath, outputPath, argc, argv);
return 0;
}
diff --git a/tools/gbagfx/util.c b/tools/gbagfx/util.c
index 5af380184..87abeb31c 100644
--- a/tools/gbagfx/util.c
+++ b/tools/gbagfx/util.c
@@ -84,6 +84,32 @@ unsigned char *ReadWholeFile(char *path, int *size)
return buffer;
}
+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);
+
+ fseek(fp, 0, SEEK_END);
+
+ *size = ftell(fp);
+
+ unsigned char *buffer = calloc(*size + padAmount, 1);
+
+ if (buffer == NULL)
+ FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
+
+ rewind(fp);
+
+ if (fread(buffer, *size, 1, fp) != 1)
+ FATAL_ERROR("Failed to read \"%s\".\n", path);
+
+ fclose(fp);
+
+ return buffer;
+}
+
void WriteWholeFile(char *path, void *buffer, int bufferSize)
{
FILE *fp = fopen(path, "wb");
diff --git a/tools/gbagfx/util.h b/tools/gbagfx/util.h
index cb26a31ef..6d7a9c21e 100644
--- a/tools/gbagfx/util.h
+++ b/tools/gbagfx/util.h
@@ -8,6 +8,7 @@
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