diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/bin2obj/.gitignore | 1 | ||||
-rw-r--r-- | tools/bin2obj/Makefile | 13 | ||||
-rw-r--r-- | tools/bin2obj/bin2obj.cpp | 295 | ||||
-rw-r--r-- | tools/nitrogfx/Makefile | 2 | ||||
-rw-r--r-- | tools/nitrogfx/gfx.c | 15 | ||||
-rw-r--r-- | tools/nitrogfx/global.h | 6 | ||||
-rw-r--r-- | tools/nitrogfx/huff.c | 28 | ||||
-rw-r--r-- | tools/nitrogfx/main.c | 6 |
8 files changed, 342 insertions, 24 deletions
diff --git a/tools/bin2obj/.gitignore b/tools/bin2obj/.gitignore new file mode 100644 index 00000000..2fa716c9 --- /dev/null +++ b/tools/bin2obj/.gitignore @@ -0,0 +1 @@ +bin2obj diff --git a/tools/bin2obj/Makefile b/tools/bin2obj/Makefile new file mode 100644 index 00000000..760a66e2 --- /dev/null +++ b/tools/bin2obj/Makefile @@ -0,0 +1,13 @@ +CXX := g++
+CXXFLAGS := -O2 -g -std=c++17
+
+.PHONY: all clean
+
+all: bin2obj
+ @:
+
+clean:
+ $(RM) bin2obj bin2obj.exe
+
+bin2obj: bin2obj.cpp
+ $(CXX) $(CXXFLAGS) -o $@ $<
diff --git a/tools/bin2obj/bin2obj.cpp b/tools/bin2obj/bin2obj.cpp new file mode 100644 index 00000000..6963438d --- /dev/null +++ b/tools/bin2obj/bin2obj.cpp @@ -0,0 +1,295 @@ +#include <iostream>
+#include <string>
+#include <vector>
+#include <fstream>
+extern "C" {
+#include <elf.h>
+}
+
+enum Proc : unsigned char {
+ PROC_ARM = EM_ARM,
+ PROC_PPC = EM_PPC,
+};
+
+enum Endian : unsigned char {
+ END_LITTLE = ELFDATA2LSB,
+ END_BIG = ELFDATA2MSB,
+};
+
+enum Shndx {
+ SHNDX_SHSTRTAB = 1,
+ SHNDX_SYMTAB,
+ SHNDX_STRTAB,
+ SHNDX_PROGBITS,
+};
+
+static inline void usage() {
+ std::cout << "Usage: bin2obj [-b|--begin SYMBOL_BEGIN]" << std::endl;
+ std::cout << " [-e|--end SYMBOL_END]" << std::endl;
+ std::cout << " [-C|--compatible]" << std::endl;
+ std::cout << " [-a|--align ALIGNMENT]" << std::endl;
+ std::cout << " [-r|--readonly]" << std::endl;
+ std::cout << " [-s|--section SECTION]" << std::endl;
+ std::cout << " [-m|--machine [arm|ppc]]" << std::endl;
+ std::cout << " [-B|--big-endian]" << std::endl;
+ std::cout << " [-L|--little-endian] BINARY_FILE OBJECT_FILE" << std::endl;
+ std::cout << std::endl;
+ std::cout << " -b or --begin Set symbol name for top of binary. (*)" << std::endl;
+ std::cout << " -e or --end Set symbol name for bottom of binary. (*)" << std::endl;
+ std::cout << " -C or --compatible Use compatible symbols with BinToElf.exe." << std::endl;
+ std::cout << " Same as \"-b _binary_%f -e _binary_%f_end\"." << std::endl;
+ std::cout << " -a or --align Set binary data alignment in bytes." << std::endl;
+ std::cout << " -r or --readonly Handle binary data as readonly." << std::endl;
+ std::cout << " -s or --section Set section name." << std::endl;
+ std::cout << " -m or --machine [arm|ppc] Machine arch [arm|ppc].(default=arm)" << std::endl;
+ std::cout << " -B or --big-endian Output in big endian format." << std::endl;
+ std::cout << " -L or --little-endian Output in little endian format." << std::endl;
+ std::cout << std::endl;
+ std::cout << " (*) special % rules for symbols (ex. binary_file = \"filename.dat\")" << std::endl;
+ std::cout << " %f,%t replaced to file name of binary (%f = \"filename.dat\")" << std::endl;
+ std::cout << " %b replaced to base name of binary (%b = \"filename\")" << std::endl;
+ std::cout << " %e replaced to extension of binary (%e = \"dat\")" << std::endl;
+}
+
+std::string& ntrsprintf(std::string& templ, std::string binfname) {
+ size_t pos;
+ if ((pos = binfname.rfind('/')) != std::string::npos) {
+ binfname = binfname.substr(pos + 1);
+ }
+ size_t extpos = binfname.rfind('.');
+ if (extpos == std::string::npos) extpos = binfname.length() - 1;
+ if ((pos = templ.find("%f")) != std::string::npos || (pos = templ.find("%t")) != std::string::npos) {
+ templ = templ.substr(0, pos) + binfname + templ.substr(pos + 2);
+ }
+ if ((pos = templ.find("%b")) != std::string::npos) {
+ templ = templ.substr(0, pos) + binfname.substr(0, extpos) + templ.substr(pos + 2);
+ }
+ if ((pos = templ.find("%e")) != std::string::npos) {
+ templ = templ.substr(0, pos) + binfname.substr(extpos + 1) + templ.substr(pos + 2);
+ }
+ return templ;
+}
+
+int main(int argc, char** argv) {
+ std::vector<std::string> args(argv + 1, argv + argc);
+ std::vector<std::string> posargs;
+ std::string sym_begin;
+ std::string sym_end;
+ bool compatible = false;
+ int alignment = 4;
+ bool readonly = false;
+ std::string section;
+ Proc proc = PROC_ARM;
+ Endian endian = END_LITTLE;
+
+ for (auto arg_i = args.cbegin(); arg_i < args.cend(); arg_i++) {
+ const std::string cur_arg = *arg_i;
+ if (cur_arg == "-b" || cur_arg == "--begin") {
+ arg_i++;
+ sym_begin = *arg_i;
+ } else if (cur_arg == "-e" || cur_arg == "--end") {
+ arg_i++;
+ sym_end = *arg_i;
+ } else if (cur_arg == "-C" || cur_arg == "--compatible") {
+ compatible = true;
+ } else if (cur_arg == "-a" || cur_arg == "--align") {
+ arg_i++;
+ try {
+ alignment = std::stoi(*arg_i);
+ } catch (std::invalid_argument& e) {
+ if (e.what() == static_cast<std::string>("stoi")) {
+ std::cerr << "Invalid integer value for " << cur_arg << ": " << *arg_i << std::endl;
+ } else {
+ std::cerr << "Unexpected error while parsing value for " << cur_arg << ": " << e.what() << std::endl;
+ }
+ return 1;
+ }
+ } else if (cur_arg == "-r" || cur_arg == "--readonly") {
+ readonly = true;
+ } else if (cur_arg == "-s" || cur_arg == "--section") {
+ arg_i++;
+ section = *arg_i;
+ } else if (cur_arg == "-m" || cur_arg == "--machine") {
+ arg_i++;
+ if (*arg_i == "arm") {
+ proc = PROC_ARM;
+ } else if (*arg_i == "ppc") {
+ proc = PROC_PPC;
+ } else {
+ std::cerr << "Invalid argument for " << cur_arg << ": " << *arg_i << std::endl;
+ return 1;
+ }
+ } else if (cur_arg == "-B" || cur_arg == "--big-endian") {
+ endian = END_BIG;
+ } else if (cur_arg == "-L" || cur_arg == "--little-endian") {
+ endian = END_LITTLE;
+ } else {
+ posargs.push_back(cur_arg);
+ }
+ }
+
+ if (posargs.size() < 2) {
+ usage();
+ std::cerr << "Missing required position argument: " << (posargs.empty() ? "BINARY_FILE" : "OBJECT_FILE") << std::endl;
+ return 1;
+ } else if (posargs.size() > 2) {
+ usage();
+ std::cerr << "Unrecognized arguments (first one: " << posargs[2] << ")" << std::endl;
+ return 1;
+ }
+ if (compatible) {
+ sym_begin = "_binary_%f";
+ sym_end = "_binary_%f_end";
+ }
+ if (sym_begin.empty()) {
+ sym_begin = "%b_begin";
+ }
+ if (sym_end.empty()) {
+ sym_end = "%b_end";
+ }
+ sym_begin = ntrsprintf(sym_begin, posargs[0]);
+ sym_end = ntrsprintf(sym_end, posargs[0]);
+ if (section.empty()) {
+ section = readonly ? ".rodata" : ".data";
+ }
+ if (alignment == 0) {
+ alignment = 1;
+ } else {
+ int i;
+ for (i = 0; i < 10; i++) {
+ if ((alignment >> i) & 1) {
+ if ((alignment >> i) & ~1) {
+ std::cerr << "Alignment must be a power of 2" << std::endl;
+ return 1;
+ }
+ break;
+ }
+ }
+ if (i == 10) {
+ std::cerr << "Alignment exceeds maximum value of 512" << std::endl;
+ return 1;
+ }
+ }
+ if (alignment < 4) {
+ alignment = 4;
+ }
+ std::ifstream binfile(posargs[0], std::ios::binary | std::ios::ate);
+ if (!binfile.good()) {
+ std::cerr << "Unable to open file " << posargs[0] << " for reading" << std::endl;
+ return 1;
+ }
+ std::ofstream objfile(posargs[1], std::ios::binary);
+ if (!objfile.good()) {
+ binfile.close();
+ std::cerr << "Unable to open file " << posargs[1] << " for writing" << std::endl;
+ return 1;
+ }
+ size_t filesize = binfile.tellg();
+ binfile.seekg(0);
+
+ // Elf header
+ Elf32_Ehdr ehdr = {
+ .e_ident = {
+ ELFMAG0, // EI_MAG0
+ ELFMAG1, // EI_MAG1
+ ELFMAG2, // EI_MAG2
+ ELFMAG3, // EI_MAG3
+ ELFCLASS32, // EI_CLASS
+ endian, // EI_DATA
+ EV_CURRENT, // EI_VERSION
+ ELFOSABI_NONE, // EI_OSABI
+ 0, // EI_ABIVERSION
+ },
+ .e_type = ET_REL,
+ .e_machine = proc,
+ .e_version = EV_CURRENT,
+ .e_shoff = sizeof(Elf32_Ehdr),
+ .e_ehsize = sizeof(Elf32_Ehdr),
+ .e_shentsize = sizeof(Elf32_Shdr),
+ .e_shnum = 5,
+ .e_shstrndx = 1,
+ };
+
+ // Five sections: NULL, user section, symtab, strtab, shstrtab
+ Elf32_Shdr shdr[5] = {};
+
+ size_t sh_name = 1;
+ shdr[SHNDX_SHSTRTAB].sh_type = SHT_STRTAB;
+ shdr[SHNDX_SHSTRTAB].sh_offset = ehdr.e_shoff + 5 * sizeof(Elf32_Shdr);
+ shdr[SHNDX_SHSTRTAB].sh_name = sh_name;
+ sh_name += std::string(".shstrtab").length() + 1;
+ shdr[SHNDX_SYMTAB].sh_type = SHT_SYMTAB;
+ shdr[SHNDX_SYMTAB].sh_link = SHNDX_STRTAB;
+ shdr[SHNDX_SYMTAB].sh_info = 2;
+ shdr[SHNDX_SYMTAB].sh_addralign = 4;
+ shdr[SHNDX_SYMTAB].sh_name = sh_name;
+ shdr[SHNDX_SYMTAB].sh_entsize = sizeof(Elf32_Sym);
+ sh_name += std::string(".symtab").length() + 1;
+ shdr[SHNDX_STRTAB].sh_type = SHT_STRTAB;
+ shdr[SHNDX_STRTAB].sh_addralign = 1;
+ shdr[SHNDX_STRTAB].sh_name = sh_name;
+ sh_name += std::string(".strtab").length() + 1;
+ shdr[SHNDX_PROGBITS].sh_type = SHT_PROGBITS;
+ shdr[SHNDX_PROGBITS].sh_flags = SHF_ALLOC | (readonly ? 0 : SHF_WRITE);
+ shdr[SHNDX_PROGBITS].sh_addralign = alignment;
+ shdr[SHNDX_PROGBITS].sh_name = sh_name;
+ sh_name += section.length() + 1;
+ shdr[SHNDX_SHSTRTAB].sh_size = sh_name;
+ sh_name = (sh_name + 3) & ~3;
+ shdr[SHNDX_SYMTAB].sh_offset = shdr[SHNDX_SHSTRTAB].sh_offset + sh_name;
+ shdr[SHNDX_SYMTAB].sh_size = 3 * sizeof(Elf32_Sym);
+ shdr[SHNDX_STRTAB].sh_offset = shdr[SHNDX_SYMTAB].sh_offset + shdr[SHNDX_SYMTAB].sh_size;
+ size_t st_name = sym_begin.length() + sym_end.length() + 3;
+ shdr[SHNDX_STRTAB].sh_size = st_name;
+ st_name = (st_name + 3) & ~3;
+ shdr[SHNDX_PROGBITS].sh_offset = shdr[SHNDX_STRTAB].sh_offset + st_name;
+ shdr[SHNDX_PROGBITS].sh_size = filesize;
+
+ // symtab
+ Elf32_Sym syms[3] = {};
+ // begin
+ syms[1].st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);
+ syms[1].st_shndx = SHNDX_PROGBITS;
+ syms[1].st_size = filesize;
+ syms[1].st_value = 0;
+ syms[1].st_name = 1;
+ // end
+ syms[2].st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);
+ syms[2].st_shndx = SHNDX_PROGBITS;
+ syms[2].st_size = 0;
+ syms[2].st_value = filesize;
+ syms[2].st_name = sym_begin.length() + 2;
+
+ // Write to file
+ char zeroes[3] = {0, 0, 0};
+ unsigned padding;
+ // Elf header
+ objfile.write((char*)&ehdr, sizeof(ehdr));
+ // Section headers
+ objfile.write((char*)shdr, sizeof(shdr));
+ // Section string table
+ objfile.write(zeroes, 1);
+ objfile.write(".shstrtab", sizeof(".shstrtab"));
+ objfile.write(".symtab", sizeof(".symtab"));
+ objfile.write(".strtab", sizeof(".strtab"));
+ objfile.write(section.c_str(), static_cast<long>(section.length() + 1));
+ padding = (4 - (sizeof(".shstrtab") + sizeof(".symtab") + sizeof(".strtab") + section.length() + 2)) & 3;
+ objfile.write(zeroes, padding);
+ // Symbol table
+ objfile.write((char*)syms, sizeof(syms));
+ // String table
+ objfile.write(zeroes, 1);
+ objfile.write(sym_begin.c_str(), static_cast<long>(sym_begin.length() + 1));
+ objfile.write(sym_end.c_str(), static_cast<long>(sym_end.length() + 1));
+ padding = (4 - (sym_begin.length() + sym_end.length() + 3)) & 3;
+ objfile.write(zeroes, padding);
+ // Data
+ char* rdbuf = new char[filesize];
+ binfile.read(rdbuf, static_cast<long>(filesize));
+ objfile.write(rdbuf, static_cast<long>(filesize));
+ delete[] rdbuf;
+
+ binfile.close();
+ objfile.close();
+ return 0;
+}
diff --git a/tools/nitrogfx/Makefile b/tools/nitrogfx/Makefile index eadf2be5..18ecdbba 100644 --- a/tools/nitrogfx/Makefile +++ b/tools/nitrogfx/Makefile @@ -1,6 +1,6 @@ CC = gcc -CFLAGS = -Wall -Wextra -Werror -Wno-sign-compare -std=c11 -O2 -DPNG_SKIP_SETJMP_CHECK +CFLAGS = -Wall -Wextra -Werror -Wno-sign-compare -std=c11 -O2 -DPNG_SKIP_SETJMP_CHECK -D_CRT_SECURE_NO_WARNINGS LIBS = -lpng -lz diff --git a/tools/nitrogfx/gfx.c b/tools/nitrogfx/gfx.c index f5ff30e7..ee7e0d6f 100644 --- a/tools/nitrogfx/gfx.c +++ b/tools/nitrogfx/gfx.c @@ -101,7 +101,7 @@ static uint32_t ConvertFromScanned4Bpp(unsigned char *src, unsigned char *dest, uint16_t val = (src[i - 1] << 8) | src[i - 2]; val ^= (encValue & 0xFFFF); src[i - 1] = (val >> 8); - src[i - 2] = val; + src[i - 2] = (unsigned char)val; encValue = encValue * 1103515245; encValue = encValue + 24691; } @@ -225,7 +225,7 @@ static void ConvertToScanned4Bpp(unsigned char *src, unsigned char *dest, int fi encValue = (encValue - 24691) * 4005161829; val ^= (encValue & 0xFFFF); dest[i] = (val >> 8); - dest[i - 1] = val; + dest[i - 1] = (unsigned char)val; } } @@ -704,7 +704,7 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in fwrite(palHeader, 1, 0x18, fp); - unsigned char colours[colourNum * 2]; + unsigned char * colours = malloc(colourNum * 2); //palette data for (int i = 0; i < colourNum; i++) { @@ -733,6 +733,7 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in } fwrite(colours, 1, colourNum * 2, fp); + free(colours); fclose(fp); } @@ -750,7 +751,7 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) { for (int j = 0; j < options->labelCount; j++) { - totalSize += strlen(options->labels[j]) + 5; //strlen + terminator + pointer + totalSize += (unsigned)strlen(options->labels[j]) + 5; //strlen + terminator + pointer } } @@ -865,7 +866,7 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) unsigned int lablSize = 8; for (int j = 0; j < options->labelCount; j++) { - lablSize += strlen(options->labels[j]) + 5; + lablSize += (unsigned)strlen(options->labels[j]) + 5; } unsigned char *labl = malloc(lablSize); @@ -884,14 +885,14 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) labl[i + 8] = position & 0xff; labl[i + 9] = position >> 8; - position += strlen(options->labels[j]) + 1; + position += (unsigned)strlen(options->labels[j]) + 1; i += 4; } for (int j = 0; j < options->labelCount; j++) { strcpy((char *) (labl + (i + 8)), options->labels[j]); - i += strlen(options->labels[j]) + 1; + i += (int)strlen(options->labels[j]) + 1; } fwrite(labl, 1, lablSize, fp); diff --git a/tools/nitrogfx/global.h b/tools/nitrogfx/global.h index 65dd351d..32378a9f 100644 --- a/tools/nitrogfx/global.h +++ b/tools/nitrogfx/global.h @@ -28,4 +28,10 @@ do { \ #endif // _MSC_VER +#define PTR_ADD(ptr, value) ((void*)((uintptr_t)(ptr) + (value))) +#define PTR_SUB(ptr, value) ((void*)((uintptr_t)(ptr) - (value))) +#define PTR_IADD(ptr, value) do { (ptr) = PTR_ADD(ptr, value); } while (0) +#define PTR_ISUB(ptr, value) do { (ptr) = PTR_SUB(ptr, value); } while (0) +#define PTR_DIFF(right, left) ((uintptr_t)(right) - (uintptr_t)(left)) + #endif // GLOBAL_H diff --git a/tools/nitrogfx/huff.c b/tools/nitrogfx/huff.c index 143ed79b..d718fb71 100644 --- a/tools/nitrogfx/huff.c +++ b/tools/nitrogfx/huff.c @@ -34,17 +34,17 @@ int msort_r(void * data, size_t count, size_t size, cmpfun cmp, void * buffer) { case 2: // Swap the two entries if the right one compares higher. - if (cmp(data, data + size) > 0) { + if (cmp(data, PTR_ADD(data, size)) > 0) { memcpy(buffer, data, size); - memcpy(data, data + size, size); - memcpy(data + size, buffer, size); + memcpy(data, PTR_ADD(data, size), size); + memcpy(PTR_ADD(data, size), buffer, size); } break; default: // Merge sort out-of-place. leftPtr = data; - leftEnd = rightPtr = data + count / 2 * size; - rightEnd = data + count * size; + leftEnd = rightPtr = PTR_ADD(data, count / 2 * size); + rightEnd = PTR_ADD(data, count * size); // Sort the left half if (!msort_r(leftPtr, count / 2, size, cmp, buffer)) @@ -58,11 +58,11 @@ int msort_r(void * data, size_t count, size_t size, cmpfun cmp, void * buffer) { i = 0; do { if (cmp(leftPtr, rightPtr) <= 0) { - memcpy(buffer + i * size, leftPtr, size); - leftPtr += size; + memcpy(PTR_ADD(buffer, i * size), leftPtr, size); + PTR_IADD(leftPtr, size); } else { - memcpy(buffer + i * size, rightPtr, size); - rightPtr += size; + memcpy(PTR_ADD(buffer, i * size), rightPtr, size); + PTR_IADD(rightPtr, size); } } while (++i < count && leftPtr < leftEnd && rightPtr < rightEnd); @@ -70,10 +70,10 @@ int msort_r(void * data, size_t count, size_t size, cmpfun cmp, void * buffer) { // Copy the remainder if (i < count) { if (leftPtr < leftEnd) { - memcpy(buffer + i * size, leftPtr, leftEnd - leftPtr); + memcpy(PTR_ADD(buffer, i * size), leftPtr, PTR_DIFF(leftEnd, leftPtr)); } else { - memcpy(buffer + i * size, rightPtr, rightEnd - rightPtr); + memcpy(PTR_ADD(buffer, i * size), rightPtr, PTR_DIFF(rightEnd, rightPtr)); } } @@ -163,7 +163,7 @@ static void write_tree(unsigned char * dest, HuffNode_t * tree, int nitems, stru if (currNode->header.isLeaf) { dest[5 + i] = traversal[i].leaf.key; } else { - dest[5 + i] = (((currNode->branch.right - traversal - i) / 2) - 1); + dest[5 + i] = (unsigned char)(((currNode->branch.right - traversal - i) / 2) - 1); if (currNode->branch.left->header.isLeaf) dest[5 + i] |= 0x80; if (currNode->branch.right->header.isLeaf) @@ -194,8 +194,8 @@ static inline void read_32_le(unsigned char * src, int * srcPos, uint32_t * buff } 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; + int nbits = (int)encoding[value].nbits; + uint32_t bitstring = (uint32_t)encoding[value].bitstring; if (*buffBits + nbits >= 32) { int diff = *buffBits + nbits - 32; diff --git a/tools/nitrogfx/main.c b/tools/nitrogfx/main.c index 171cb5f3..b2d3352a 100644 --- a/tools/nitrogfx/main.c +++ b/tools/nitrogfx/main.c @@ -63,13 +63,14 @@ void ConvertNtrToPng(char *inputPath, char *outputPath, struct GbaToPngOptions * if (key) { - char string[strlen(outputPath) + 5]; + char* string = malloc(strlen(outputPath) + 5); sprintf(string, "%s.key", outputPath); FILE *fp = fopen(string, "wb"); if (fp == NULL) FATAL_ERROR("Failed to open key file for writing.\n"); fwrite(&key, 4, 1, fp); fclose(fp); + free(string); } image.hasTransparency = options->hasTransparency; @@ -103,7 +104,7 @@ void ConvertPngToNtr(char *inputPath, char *outputPath, struct PngToNtrOptions * uint32_t key = 0; if (options->scanned) { - char string[strlen(inputPath) + 5]; + char* string = malloc(strlen(inputPath) + 5); sprintf(string, "%s.key", inputPath); FILE *fp2 = fopen(string, "rb"); if (fp2 == NULL) @@ -112,6 +113,7 @@ void ConvertPngToNtr(char *inputPath, char *outputPath, struct PngToNtrOptions * if (count != 1) FATAL_ERROR("Not a valid key file.\n"); fclose(fp2); + free(string); } WriteNtrImage(outputPath, options->numTiles, image.bitDepth, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette, options->clobberSize, options->byteOrder, options->version101, options->sopc, options->scanned, key); |