diff options
author | YamaArashi <shadow962@live.com> | 2016-01-29 03:55:59 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-01-29 03:55:59 -0800 |
commit | aa5f55985df95a853c30aecd21cde8c4663810d5 (patch) | |
tree | d08ef1b960ac66c41dbf89ddd2628c7b91e98d48 /tools | |
parent | 3a5e05377e844f62911633e7ff8da7a3d37cd2b2 (diff) |
tilesets
Diffstat (limited to 'tools')
-rw-r--r-- | tools/gbagfx/lz.c | 30 | ||||
-rw-r--r-- | tools/gbagfx/main.c | 39 | ||||
-rw-r--r-- | tools/gbagfx/util.c | 26 | ||||
-rw-r--r-- | tools/gbagfx/util.h | 1 |
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 |