summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPikalaxALT <pikalaxalt@gmail.com>2019-06-23 19:29:44 -0400
committerPikalaxALT <pikalaxalt@gmail.com>2019-06-23 19:29:44 -0400
commit8e7a1dac011e7e96d1220106c3865743f3e34175 (patch)
treec485906f5685aa239d20f125911c687aae2c4593
parent64498f41072ee4a3f27c7b716a46c2952afa4721 (diff)
Initial attempt to bootstrap Travis CI
-rw-r--r--.travis.yml35
-rw-r--r--.travis/calcrom/webhook.sh16
-rw-r--r--baserom.ipsbin0 -> 2401387 bytes
-rw-r--r--data/data_83FECCC.s2
-rw-r--r--data/graphics.s3
-rw-r--r--tools/br_ips/Makefile13
-rw-r--r--tools/br_ips/br_ips.c249
-rw-r--r--tools/br_ips/ips_patch.c63
8 files changed, 378 insertions, 3 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..af94cfe81
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,35 @@
+language: generic
+dist: trusty
+sudo: false
+addons:
+ apt:
+ packages:
+ - gcc-multilib
+ - linux-libc-dev
+ - zlib-dev
+cache:
+ apt: true
+install:
+ - pushd $HOME
+ - travis_retry git clone https://github.com/luckytyphlosion/agbcc.git -b new_layout_with_libs
+ - cd agbcc && make && make install prefix=$TRAVIS_BUILD_DIR
+ - popd
+matrix:
+ include:
+ - os: linux
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-7
+ env: _="Build"
+ script:
+ - head -c 16777216 /dev/zero > tmp.bin
+ - make ips_patch -C tools/br_ips
+ - tools/br_ips/ips_patch tmp.bin baserom.ips baserom.gba
+ - rm tmp.bin
+ - make tools CXX=g++-7
+ - make -j2 compare
+after_success:
+ - .travis/calcrom/webhook.sh pokefirered
diff --git a/.travis/calcrom/webhook.sh b/.travis/calcrom/webhook.sh
new file mode 100644
index 000000000..86da74c87
--- /dev/null
+++ b/.travis/calcrom/webhook.sh
@@ -0,0 +1,16 @@
+#!/bin/bash -ex
+
+# Only run this script if it's the master branch build.
+if [[ "$TRAVIS_BRANCH" != "master" || "$TRAVIS_PULL_REQUEST" != "false" ]]; then
+ exit 0
+fi
+
+build_name=$1
+map_file=$build_name.map
+if [ ! -f $map_file ]; then
+ echo "$map_file does not exist!"
+ exit 1
+fi
+
+output=$(perl $(dirname "$0")/calcrom.pl $build_name.map | sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g')
+curl -d "{\"username\": \"$CALCROM_DISCORD_WEBHOOK_USERNAME\", \"avatar_url\": \"$CALCROM_DISCORD_WEBHOOK_AVATAR_URL\", \"content\":\"\`\`\`$build_name progress:\\n$output\`\`\`\"}" -H "Content-Type: application/json" -X POST $CALCROM_DISCORD_WEBHOOK_URL
diff --git a/baserom.ips b/baserom.ips
new file mode 100644
index 000000000..c28018137
--- /dev/null
+++ b/baserom.ips
Binary files differ
diff --git a/data/data_83FECCC.s b/data/data_83FECCC.s
index 1a1ab6d0a..30a3f101a 100644
--- a/data/data_83FECCC.s
+++ b/data/data_83FECCC.s
@@ -665,7 +665,7 @@ gUnknown_843EE64:: @ 843EE64
.asciz "SEARCH"
.align 2
- .incbin "baserom.gba", 0x43EEC0, 0x43F004-0x43EEC0
+ .incbin "baserom.gba", 0x43EEC0, 0x144
gUnknown_843F004:: @ 843F004
.incbin "baserom.gba", 0x43F004, 0x100
diff --git a/data/graphics.s b/data/graphics.s
index 35d5873fa..b655cadc7 100644
--- a/data/graphics.s
+++ b/data/graphics.s
@@ -16412,5 +16412,4 @@ gUnknown_8EAFFC0:: @ 8EAFFC0
gUnknown_8EB0ADC:: @ 8EB0ADC
.incbin "baserom.gba", 0xEB0ADC, 0x44
-gUnknown_8EB0B20:: @ 8EB0B20
- .incbin "baserom.gba", 0xEB0B20
+ @ EOF
diff --git a/tools/br_ips/Makefile b/tools/br_ips/Makefile
new file mode 100644
index 000000000..e80e2576b
--- /dev/null
+++ b/tools/br_ips/Makefile
@@ -0,0 +1,13 @@
+CC := gcc
+CFLAGS := -O3
+
+all: br_ips ips_patch
+
+clean:
+ rm -f br_ips ips_patch br_ips.exe ips_patch.exe
+
+br_ips: br_ips.c
+ $(CC) $(CFLAGS) -o $@ $^
+
+ips_patch: ips_patch.c
+ $(CC) $(CFLAGS) -o $@ $^
diff --git a/tools/br_ips/br_ips.c b/tools/br_ips/br_ips.c
new file mode 100644
index 000000000..140bc3891
--- /dev/null
+++ b/tools/br_ips/br_ips.c
@@ -0,0 +1,249 @@
+#define _POSIX_C_SOURCE 200808L // Don't use GNU getline
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+
+#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)
+
+#endif // _MSC_VER
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef int ssize_t;
+#endif // _SSIZE_T
+
+static const char SPLASH[] = "IPS patch creator for undisassembled data\n"
+ "Created by PikalaxALT on 23 June 2019 All Rights Reserved\n";
+
+struct Baserom {
+ uint32_t offset;
+ size_t size;
+};
+
+static ssize_t getline(char ** lineptr, size_t * n, FILE * stream) {
+ ssize_t i = 0;
+ int c;
+ size_t size = *n;
+ char * buf = *lineptr;
+ if (size == 0) {
+ size = BUFSIZ;
+ buf = realloc(buf, BUFSIZ);
+ }
+ if (buf == NULL) return -1;
+ do {
+ if (feof(stream)) return -1;
+ c = getc(stream);
+ buf[i++] = c;
+ if (i == size) {
+ size <<= 1;
+ buf = realloc(buf, size);
+ if (buf == NULL) return -1;
+ }
+ } while (c != '\n');
+
+ *lineptr = buf;
+ *n = size;
+ return i;
+}
+
+static void getIncbinsFromFile(struct Baserom ** incbins, size_t * num, size_t * maxnum, const char * fname, char ** strbuf, size_t * buffersize) {
+ FILE * file = fopen(fname, "r");
+ if (file == NULL) FATAL_ERROR("unable to open file \"%s\" for reading\n", fname);
+ struct Baserom * data = *incbins;
+ size_t nincbins = *num;
+ size_t maxnincbins = *maxnum;
+ int line_n = 0;
+ while (getline(strbuf, buffersize, file) > 0) {
+ line_n++;
+ char * nl_p = strchr(*strbuf, '\n');
+ if (nl_p != NULL) *nl_p = 0;
+ char * include = strstr(*strbuf, ".include");
+ if (include != NULL) {
+ char incfname[128];
+ include = strchr(include, '"');
+ if (include == NULL) FATAL_ERROR("%s:%d: malformed include\n", fname, line_n);
+ include++;
+ char * endq_p = strchr(include, '"');
+ if (endq_p == NULL) FATAL_ERROR("%s:%d: malformed include\n", fname, line_n);
+ *endq_p = 0;
+ strcpy(incfname, include);
+ getIncbinsFromFile(&data, &nincbins, &maxnincbins, incfname, strbuf, buffersize);
+ continue;
+ }
+ char * line = strstr(*strbuf, ".incbin");
+ if (line == NULL) continue;
+ line = strstr(line + sizeof(".incbin"), "\"baserom.gba\",");
+ if (line == NULL) continue;
+ line += sizeof("\"baserom.gba\",") - 1;
+ uint32_t incbinOffset;
+ do {
+ if (*line == 0) FATAL_ERROR("%s:%d: malformed incbin\n", fname, line_n);
+ incbinOffset = strtoul(line, &line, 0);
+ line++;
+ } while (incbinOffset == 0);
+ ssize_t incbinSize;
+ do {
+ if (*line == 0) FATAL_ERROR("%s:%d: malformed incbin\n", fname, line_n);
+ incbinSize = strtoul(line, &line, 0);
+ line++;
+ } while (incbinSize == 0);
+ if (incbinOffset >= 0x01000000) FATAL_ERROR("%s:%d: offset exceeds encodable limit\n", fname, line_n);
+ if (incbinOffset == 0x454F46) { // "EOF"
+ incbinOffset--;
+ incbinSize++;
+ }
+ if (incbinOffset + incbinSize >= 0xFFFFFF + 0xFFFF) FATAL_ERROR("%s:%d: size exceeds encodable limit\n", fname, line_n);
+ do {
+ size_t trueSize = incbinSize <= 0xFFFF ? incbinSize : 0xFFFF;
+ if (nincbins >= maxnincbins) {
+ maxnincbins <<= 1;
+ data = realloc(data, maxnincbins * sizeof(struct Baserom));
+ if (data == NULL) FATAL_ERROR("unable to reallocate incbins buffer\n");
+ }
+ // fprintf(stderr, "DEBUG: %s:%d: 0x%x, 0x%lx\n", fname, line_n, incbinOffset, trueSize);
+ data[nincbins].offset = incbinOffset;
+ data[nincbins].size = trueSize;
+ incbinOffset += trueSize;
+ incbinSize -= trueSize;
+ if (incbinOffset == 0x454F46) {
+ incbinOffset--;
+ data[nincbins].size--;
+ incbinSize++;
+ }
+ nincbins++;
+ } while (incbinSize > 0);
+ }
+ if (!feof(file)) FATAL_ERROR("getline\n");
+ fclose(file);
+ *incbins = data;
+ *num = nincbins;
+ *maxnum = maxnincbins;
+}
+
+static struct Baserom * getAllIncbins(FILE * ld_script, size_t * num_p) {
+ char * line = NULL;
+ size_t linesiz = 0;
+ char fname_buf[128];
+ size_t maxnum = 256;
+ size_t num = 0;
+ struct Baserom * incbins = malloc(256 * sizeof(struct Baserom));
+ if (incbins == NULL) FATAL_ERROR("failed to allocate incbins buffer\n");
+ while (getline(&line, &linesiz, ld_script) > 0) {
+ char * endptr;
+ if ((endptr = strstr(line, ".o(.rodata);")) == NULL
+ && (endptr = strstr(line, ".o(script_data);")) == NULL
+ && (endptr = strstr(line, ".o(gfx_data);")) == NULL) continue;
+ char * startptr = line;
+ while (isspace(*startptr)) startptr++;
+ if (strstr(startptr, ".a:") != NULL) continue; // no incbins in libs
+ if (strstr(startptr, "src/") == startptr) continue; // no incbins in src/
+ endptr[1] = 's';
+ endptr[2] = 0;
+ strcpy(fname_buf, startptr);
+ getIncbinsFromFile(&incbins, &num, &maxnum, fname_buf, &line, &linesiz);
+ }
+ if (!feof(ld_script)) FATAL_ERROR("getline\n");
+ free(line);
+ *num_p = num;
+ return incbins;
+}
+
+static int cmp_baserom(const void * a, const void * b) {
+ const struct Baserom * aa = (const struct Baserom *)a;
+ const struct Baserom * bb = (const struct Baserom *)b;
+ return (aa->offset > bb->offset) - (aa->offset < bb->offset);
+}
+
+static void collapseIncbins(struct Baserom * incbins, size_t * num_p) {
+ size_t num = *num_p;
+ qsort(incbins, num, sizeof(struct Baserom), cmp_baserom);
+ for (int i = 0; i < num - 1; i++) {
+ while (incbins[i].offset + incbins[i].size == incbins[i + 1].offset) {
+ if (incbins[i].size == 0xFFFF) break;
+ while (incbins[i].size == 0) {
+ for (int j = i; j < num - 1; j++) incbins[j] = incbins[j + 1];
+ num--;
+ if (i == num - 1) break;
+ }
+ if (i == num - 1) break;
+ incbins[i].size += incbins[i + 1].size;
+ if (incbins[i].size > 0xFFFF) {
+ incbins[i + 1].size = incbins[i].size - 0xFFFF;
+ incbins[i].size = 0xFFFF;
+ incbins[i + 1].offset = incbins[i].offset + 0xFFFF;
+ if (incbins[i + 1].offset == 0x454F46) {
+ incbins[i].size--;
+ incbins[i + 1].offset--;
+ incbins[i + 1].size++;
+ }
+ break;
+ } else {
+ for (int j = i + 1; j < num - 1; j++) incbins[j] = incbins[j + 1];
+ num--;
+ if (i == num - 1) break;
+ }
+ }
+ }
+ *num_p = num;
+}
+
+static void writePatch(const char * filename, const struct Baserom * incbins, size_t num, FILE * rom) {
+ FILE * file = fopen(filename, "wb");
+ if (file == NULL) FATAL_ERROR("unable to open file \"%s\" for writing\n", filename);
+ char * readbuf = malloc(0x10000);
+ if (readbuf == NULL) FATAL_ERROR("failed to allocate write buffer\n");
+ fwrite("PATCH", 1, 5, file); // magic
+ for (int i = 0; i < num; i++) {
+ uint32_t offset = incbins[i].offset;
+ putc(offset >> 16, file);
+ putc(offset >> 8, file);
+ putc(offset >> 0, file);
+ size_t size = incbins[i].size;
+ putc(size >> 8, file);
+ putc(size >> 0, file);
+ if (fseek(rom, offset, SEEK_SET)) FATAL_ERROR("seek\n");
+ if (fread(readbuf, 1, size, rom) != size) FATAL_ERROR("read\n");
+ if (fwrite(readbuf, 1, size, file) != size) FATAL_ERROR("write\n");
+ printf("DEBUG: 0x%x, 0x%lx\n", offset, size);
+ }
+ free(readbuf);
+ fwrite("EOF", 1, 3, file);
+ fclose(file);
+}
+
+int main() {
+ puts(SPLASH);
+ FILE * rom = fopen("baserom.gba", "rb");
+ if (rom == NULL) FATAL_ERROR("unable to open \"baserom.gba\" for reading\n");
+ FILE * ld_script = fopen("ld_script.txt", "r");
+ if (ld_script == NULL) FATAL_ERROR("unable to open \"ld_script.txt\" for reading\n");
+ size_t num = 0;
+ struct Baserom * incbins = getAllIncbins(ld_script, &num);
+ fclose(ld_script);
+ if (num == 0) {
+ puts("No baserom.gba incbins found!\n");
+ } else {
+ collapseIncbins(incbins, &num);
+ writePatch("baserom.ips", incbins, num, rom);
+ }
+ fclose(rom);
+ free(incbins);
+ puts("IPS file created at baserom.ips\n");
+ return 0;
+}
diff --git a/tools/br_ips/ips_patch.c b/tools/br_ips/ips_patch.c
new file mode 100644
index 000000000..03780cf72
--- /dev/null
+++ b/tools/br_ips/ips_patch.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#ifdef _MSC_VER
+
+#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)
+
+#endif // _MSC_VER
+
+static const char SPLASH[] = "Small IPS patch utility\n"
+ "Created by PikalaxALT on 23 June 2019 All Rights Reserved\n";
+
+int main(int argc, char ** argv) {
+ puts(SPLASH);
+ if (argc != 4) FATAL_ERROR("usage: %s ROM PATCH OUT\n", argv[0]);
+ FILE * rom = fopen(argv[1], "rb");
+ if (rom == NULL) FATAL_ERROR("failed to open file \"%s\" for reading\n", argv[1]);
+ FILE * patch = fopen(argv[2], "rb");
+ if (patch == NULL) FATAL_ERROR("failed to open file \"%s\" for reading\n", argv[2]);
+ FILE * out = fopen(argv[3], "wb");
+ if (patch == NULL) FATAL_ERROR("failed to open file \"%s\" for writing\n", argv[3]);
+ char magic[5];
+ if (fread(magic, 1, 5, patch) != 5) FATAL_ERROR("read magic\n");
+ if (memcmp(magic, "PATCH", 5) != 0) FATAL_ERROR("malformed IPS patch\n");
+ fseek(rom, 0, SEEK_END);
+ size_t romsize = ftell(rom);
+ fseek(rom, 0, SEEK_SET);
+ char * buffer = malloc(romsize);
+ if (buffer == NULL) FATAL_ERROR("failed to allocate dest buffer\n");
+ if (fread(buffer, 1, romsize, rom) != romsize) FATAL_ERROR("read ROM\n");
+ fclose(rom);
+ while (1) {
+ uint32_t offset;
+ size_t size;
+
+ offset = (unsigned char)getc(patch) << 16;
+ offset |= (unsigned char)getc(patch) << 8;
+ offset |= (unsigned char)getc(patch);
+ if (offset == 0x454F46) break;
+ size = (unsigned char)getc(patch) << 8;
+ size |= (unsigned char)getc(patch);
+ if (fread(buffer + offset, 1, size, patch) != size) FATAL_ERROR("read segment\n");
+ }
+ fclose(patch);
+ fwrite(buffer, 1, romsize, out);
+ fclose(out);
+ free(buffer);
+ return 0;
+}