]> Chaos Git - corbenik/corbenik.git/commitdiff
Add a early-ish prototype ips2pco tool.
authorchaoskagami <chaos.kagami@gmail.com>
Wed, 28 Dec 2016 22:56:12 +0000 (17:56 -0500)
committerchaoskagami <chaos.kagami@gmail.com>
Wed, 28 Dec 2016 23:00:24 +0000 (18:00 -0500)
This tool takes an IPS or IPS32 patch and creates a .pco (bytecode source) skeleton. This is based on a previously written tool in my libbinmod repository for actually creating/applying IPS patches. The core changes to blib.c/blib.h will make it there soon-ish.

This can be used to automate conversion of IPS patches to a format compatible with corbenik's patcher system. Do note the output files are not ready for use as-is -- you will need to manually edit the name, description, and titleID as needed, as well as actually run it through bytecode_asm.py.

host/Makefile
host/ips2pco/Makefile [new file with mode: 0644]
host/ips2pco/bips.c [new file with mode: 0755]
host/ips2pco/blib.c [new file with mode: 0755]
host/ips2pco/blib.h [new file with mode: 0755]
host/ips2pco/ips_fmt.h [new file with mode: 0755]
host/ips2pco/util.c [new file with mode: 0755]
host/ips2pco/util.h [new file with mode: 0755]

index 4c486d2ac8c38d6feaf336e217f2d7455c6f3a92..816f6a1bf668adaa349d3221ef41d11115a36650 100644 (file)
@@ -3,12 +3,16 @@ all: bdfe font misc
 misc:
        gcc -o error_decoder error_decoder.c -g -O0
 
+ips2pco:
+       $(MAKE) -C ips2pco
+
 bdfe_dir:
-       make -C bdfe
+       $(MAKE) -C bdfe
 
 font: bdfe_dir
        ./bdfe/bdfe -n -A ../external/tewi-font/tewi-medium-11.bdf > termfont.bin
 
 clean:
+       $(MAKE) -C ips2pco clean
        $(MAKE) -C bdfe clean
        rm -f termfont.bin key_char error_decoder
diff --git a/host/ips2pco/Makefile b/host/ips2pco/Makefile
new file mode 100644 (file)
index 0000000..940867e
--- /dev/null
@@ -0,0 +1,22 @@
+CXX = gcc
+CFLAGS = -Wall -Werror
+CFLAGS += -g
+#CFLAGS += -O3
+LIBS    =
+
+CORE = ips2pco
+OBJS = bips.o blib.o util.o
+HFILES = Makefile
+CFILES = bips.c blib.c util.c
+
+all: $(CORE)
+
+$(CORE): $(OBJS) $(CFILES) $(HFILES)
+       $(CXX) $(CFLAGS) -o $(CORE) $(OBJS) $(LIBS)
+
+clean:
+       rm -f $(CORE)
+       rm -f *.o
+
+%.o: %.c $(HFILES)
+       $(CXX) -c $(CFLAGS) -DOSSD_TARGET=OSSD_IF_LINUX $< -o $@
diff --git a/host/ips2pco/bips.c b/host/ips2pco/bips.c
new file mode 100755 (executable)
index 0000000..4a128f1
--- /dev/null
@@ -0,0 +1,350 @@
+/* bips - A IPS patcher tool */
+
+#include "blib.h"
+#include "ips_fmt.h"
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+uint8_t* ips_buffer = NULL;
+
+int simulate  = 0; // Don't actually apply; only show the results.
+int plaintext = 0; // Decompile IPS to a human-readable listing.
+int splitmini = 0; // Split IPS to one chunk mini-ips patches in a folder.
+
+// On success, returns the number of IPS records read. On failure,
+// returns -1.
+int load_ips(__READ char* ips_filename, __WRITE ips_record_t** ips_structs) {
+       // We load the entire thing to memory.
+
+       FILE* f = fopen(ips_filename, "r");
+       fseek(f, 0, SEEK_END);
+       uint64_t pos = ftell(f);
+       rewind(f);
+
+       ips_buffer = (uint8_t*)malloc(pos);
+
+       fread(ips_buffer, 1, pos, f);
+
+       fclose(f);
+
+       printf("Loaded file to memory successfully. Size: %lu\n", pos);
+
+       // Loaded. Begin by checking shit.
+       if( strncmp((const char*)ips_buffer, IPS_MAGIC, IPS_MAGIC_LENGTH) ) {
+               // Invalid signature. Not an IPS.
+               free(ips_buffer);
+               ips_buffer = NULL;
+               return -1;
+       }
+
+       // Seems legit. Begin record calculation.
+       int ips_count = 0;
+       uint64_t offset_in = 5;
+       ips_record_t* ips_data = NULL;
+       while( offset_in < pos && strncmp((char*)&ips_buffer[offset_in], IPS_TAIL, IPS_TAIL_LENGTH) ) {
+               // Increment.
+               ips_count++;
+
+               // Reallocate.
+               ips_data = (ips_record_t*)realloc(ips_data, sizeof(ips_record_t) * ips_count);
+
+               ips_data[ips_count-1].info = (ips_record_com_t*)&ips_buffer[offset_in];
+
+               offset_in += sizeof(ips_record_com_t);
+
+               ips_data[ips_count-1].data = (void*)&ips_buffer[offset_in];
+
+               if(ips_data[ips_count-1].info->size[0] == 0x00 && ips_data[ips_count-1].info->size[1] == 0x00) // Zero is zero regardless of byte order, no casting needed
+                       // RLE. Add the size of an RLE struct.
+                       offset_in += sizeof(ips_record_rle_t);
+               else
+                       offset_in += BYTE2_TO_UINT16(ips_data[ips_count-1].info->size);
+
+               // Aaand onto the next.
+       }
+
+       printf("Read in IPS data. Record count: %d\n", ips_count);
+
+       ips_structs[0] = ips_data;
+
+       return ips_count;
+}
+
+int conv_ips(__READ char* filename, __READ ips_record_t* records, __READ int record_count) {
+       FILE* out = stdout;
+       if (filename != NULL) {
+               out = fopen(filename, "wb");
+               if (!out) {
+                       fprintf(stderr, "Can't open. Writing to stdout.\n");
+                       out = stdout;
+               }
+       }
+
+       srand(time(NULL));
+       uint16_t uuid = (0x6600 + (rand() % 0x4400));
+       
+       fprintf(out, "# $name  EDITME\n");
+       fprintf(out, "# $desc  Converted IPS Patch\n");
+       fprintf(out, "# $title EDITME\n");
+       fprintf(out, "# $ver   01\n");
+       fprintf(out, "# $uuid  %04hx\n", uuid);
+       fprintf(out, "# This file was automatically generated by ips2pco\n");
+
+       for (int i=0; i < record_count; i++) {
+               uint32_t offset = BYTE3_TO_UINT32(records[i].info->offset);
+               uint16_t size = BYTE2_TO_UINT16(records[i].info->size);
+               
+               fprintf(out, "seek %08x\n", offset);
+
+               if (size == 0) { // RLE
+                       ips_record_rle_t* rle = (ips_record_rle_t*)records[i].data;
+
+                       size = BYTE2_TO_UINT16(rle->rle_size);
+
+                       for (int i=0; i < size; i += 0x20) {
+                               uint32_t max_l = (size - i > 0x20) ?
+                                       0x20 :
+                                       size - i;
+                               fprintf(out, "set  ");
+
+                               for(uint32_t j=0; j < max_l; j++)
+                                       fprintf(out, "%02hhx", rle->byte);
+                               fprintf(out, "\n");
+                       }
+               } else { // Normal
+                       uint8_t* bytes = (uint8_t*)records[i].data;
+                       
+                       for (int i=0; i < size; i += 0x20) {
+                               uint32_t max_l = (size - i > 0x20) ?
+                                       0x20 :
+                                       size - i;
+                               fprintf(out, "set  ");
+
+                               for(uint32_t j=0; j < max_l; j++)
+                                       fprintf(out, "%02hhx", bytes[i+j]);
+                               fprintf(out, "\n");
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+// On success, returns the number of IPS records read. On failure,
+// returns -1.
+int load_ips32(__READ char* ips_filename, __WRITE ips32_record_t** ips_structs) {
+       // We load the entire thing to memory.
+
+       FILE* f = fopen(ips_filename, "r");
+       fseek(f, 0, SEEK_END);
+       uint64_t pos = ftell(f);
+       rewind(f);
+
+       ips_buffer = (uint8_t*)malloc(pos);
+
+       fread(ips_buffer, 1, pos, f);
+
+       fclose(f);
+
+       printf("Loaded file to memory successfully. Size: %lu\n", pos);
+
+       // Loaded. Begin by checking shit.
+       if( strncmp((const char*)ips_buffer, IPS32_MAGIC, IPS32_MAGIC_LENGTH) ) {
+               // Invalid signature. Not an IPS.
+               free(ips_buffer);
+               ips_buffer = NULL;
+               return -1;
+       }
+
+       // Seems legit. Begin record calculation.
+       int ips_count = 0;
+       uint64_t offset_in = 5;
+       ips32_record_t* ips_data = NULL;
+       while( offset_in < pos && strncmp((char*)&ips_buffer[offset_in], IPS32_TAIL, IPS32_TAIL_LENGTH) ) {
+               // Increment.
+               ips_count++;
+
+               // Reallocate.
+               ips_data = (ips32_record_t*)realloc(ips_data, sizeof(ips32_record_t) * ips_count);
+
+               ips_data[ips_count-1].info = (ips32_record_com_t*)&ips_buffer[offset_in];
+
+               offset_in += sizeof(ips32_record_com_t);
+
+               ips_data[ips_count-1].data = (void*)&ips_buffer[offset_in];
+
+               if(ips_data[ips_count-1].info->size[0] == 0x00 && ips_data[ips_count-1].info->size[1] == 0x00) { // Zero is zero regardless of byte order, no casting needed
+                       // RLE. Add the size of an RLE struct.
+                       offset_in += sizeof(ips32_record_rle_t);
+               } else {
+                       offset_in += BYTE2_TO_UINT16(ips_data[ips_count-1].info->size);
+               }
+
+               // Aaand onto the next.
+       }
+
+       printf("Read in IPS data. Record count: %d\n", ips_count);
+
+       ips_structs[0] = ips_data;
+
+       return ips_count;
+}
+
+int conv_ips32(__READ char* filename, __READ ips32_record_t* records, __READ int record_count) {
+       FILE* out = stdout;
+       if (filename != NULL) {
+               out = fopen(filename, "wb");
+               if (!out) {
+                       fprintf(stderr, "Can't open. Writing to stdout.\n");
+                       out = stdout;
+               }
+       }
+       
+       srand(time(NULL));
+       uint16_t uuid = (0x6600 + (rand() % 0x4400));
+       
+       fprintf(out, "# $name  EDITME\n");
+       fprintf(out, "# $desc  Converted IPS Patch\n");
+       fprintf(out, "# $title EDITME\n");
+       fprintf(out, "# $ver   01\n");
+       fprintf(out, "# $uuid  %04hx\n", uuid);
+       fprintf(out, "# This file was automatically generated by ips2pco\n");
+       
+       for (int i=0; i < record_count; i++) {
+               uint32_t offset = BYTE4_TO_UINT32(records[i].info->offset);
+               uint16_t size = BYTE2_TO_UINT16(records[i].info->size);
+               
+               fprintf(out, "seek %08x\n", offset);
+
+               if (size == 0) { // RLE
+                       ips32_record_rle_t* rle = (ips32_record_rle_t*)records[i].data;
+
+                       size = BYTE2_TO_UINT16(rle->rle_size);
+
+                       for (int i=0; i < size; i += 0x20) {
+                               uint32_t max_l = (size - i > 0x20) ?
+                                       0x20 :
+                                       size - i;
+                               fprintf(out, "set  ");
+
+                               for(uint32_t j=0; j < max_l; j++)
+                                       fprintf(out, "%02hhx", rle->byte);
+                               fprintf(out, "\n");
+                       }
+               } else { // Normal
+                       uint8_t* bytes = (uint8_t*)records[i].data;
+                       
+                       for (int i=0; i < size; i += 0x20) {
+                               uint32_t max_l = (size - i > 0x20) ?
+                                       0x20 :
+                                       size - i;
+                               fprintf(out, "set  ");
+
+                               for(uint32_t j=0; j < max_l; j++)
+                                       fprintf(out, "%02hhx", bytes[i+j]);
+                               fprintf(out, "\n");
+                       }
+               }
+       }
+       
+       if (out != stdout)
+               fclose(out);
+
+       return 0;
+}
+
+
+int identify_patch(__READ char* filename) {
+       char test[8];
+       FILE* f = fopen(filename, "r");
+       fseek(f, 0, SEEK_END);
+       if (ftell(f) < 8) {
+               // Wrong. No patch is smaller than this. Die.
+               return TYPE_INVALID;
+       }
+       rewind(f);
+       fread(test, 1, 8, f);
+
+       fclose(f);
+
+       if ( !strncmp(test, IPS_MAGIC, IPS_MAGIC_LENGTH) )
+               return TYPE_IPS;
+       if ( !strncmp(test, IPS32_MAGIC, IPS32_MAGIC_LENGTH) )
+               return TYPE_IPS32;
+
+       return TYPE_INVALID;
+}
+
+void help(char* name) {
+       printf("corbenik ips2pco v0.1\n");
+       printf("(C) 2015 Jon Feldman (@chaoskagami) <kagami@chaos.moe>\n");
+       printf("Usage:\n");
+       printf("   %s [options] patch.ips [out.pco]\n", name);
+       printf("Options:\n");
+       printf("   -h        Print this help text.\n");
+       printf("Patch is dumped to stdout if a output file is not specified.\n");
+       printf("Report bugs to <https://github.com/chaoskagami/corbenik>\n");
+       printf("This software is licensed under the MIT license.\n");
+
+}
+
+int main(int argc, char** argv) {
+       ips_record_t*   ips   = NULL;
+       ips32_record_t* ips32 = NULL;
+       int record_count = 0;
+       int opt;
+       int prog_ret = 0;
+
+       while ( (opt = getopt(argc, argv, "hs")) != -1) {
+               switch(opt) {
+                       case 'h':
+                               help(argv[0]);
+                               return 1;
+                       case 's':
+                               simulate = 1;
+                               break;
+                       case '?':
+                               fprintf(stderr, "error: unknown option. Run with -h for more info\n");
+                               return 1;
+                       default:
+                               fprintf(stderr, "error: unknown option. Run with -h for more info\n");
+                               return 1;
+               }
+       }
+
+       if (argc - optind < 1) {
+               fprintf(stderr, "error: requires more arguments. Run with -h for more info\n");
+               return 1;
+       }
+
+       char* patch  = argv[optind];
+       int type = identify_patch(patch);
+       char *out_file = NULL;
+       if (argc - optind >= 2) {
+               out_file  = argv[optind+1];
+       }
+
+       switch(type) {
+               case TYPE_IPS:
+                       fprintf(stderr, "Patch format: IPS (24-bit offsets)\n");
+                       record_count = load_ips(patch, &ips);
+                       conv_ips(out_file, ips, record_count);
+                       break;
+               case TYPE_IPS32:
+                       fprintf(stderr, "Patch format: IPS32 (IPS derivative w/ 32-bit offsets)\n");
+                       record_count = load_ips32(patch, &ips32);
+                       conv_ips32(out_file, ips32, record_count);
+                       break;
+               default:
+                       fprintf(stderr, "Patch format not understood or invalid.\n");
+                       prog_ret = -2;
+                       break;
+       }
+               
+       free(ips);
+       free(ips32);
+       free(ips_buffer);
+       
+       return prog_ret;
+}
diff --git a/host/ips2pco/blib.c b/host/ips2pco/blib.c
new file mode 100755 (executable)
index 0000000..d14e888
--- /dev/null
@@ -0,0 +1,197 @@
+#define BLIB_NO_EXTERNS
+
+#include "blib.h"
+
+int            blib_filefd;
+unsigned char* blib_buffer;
+struct stat    blib_stat;
+
+int copy_file(__READ char* dest, __READ char* src) {
+       // Can you believe there's no standard method to copy files? Neither can I.
+       // We use the generic POSIX way.
+
+       int in_fd = open(src, O_RDONLY);
+       if(in_fd <= 0)
+               goto error_copy_file;
+
+       int out_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+       if (out_fd <= 0)
+               goto error_copy_file;
+
+       char buf[8192];
+
+       while (1) {
+               ssize_t result = read(in_fd, buf, sizeof(buf));
+
+               if (!result) // Done?
+                       break;
+
+               if(result < 0) {
+                       // ERROR!
+                       fprintf(stderr, "Negative bytes read?\n");
+                       goto error_copy_file;
+               }
+
+               if (write(out_fd, buf, result) != result) {
+                       // Short write? Out of disk, maybe. Either way, abort.
+                       fprintf(stderr, "Short write?\n");
+                       goto error_copy_file;
+               }
+       }
+
+       close(in_fd);
+       close(out_fd);
+
+       return 0;
+
+error_copy_file:
+       if (in_fd) close(in_fd);
+       if (out_fd) close(out_fd);
+
+       return 1;
+}
+
+int hexdump_file(__READ uint8_t *buffer, __READ uint64_t len, __READ int format) {
+       return hexdump_manual(0, buffer, len, format, stdout);
+}
+
+int hexdump_manual(__READ uint64_t offset, __READ uint8_t* buffer, __READ uint64_t len, __READ int format, FILE* output) {
+       // Okay, hexdump.
+
+       for (int i = 0; i < len;) {
+               int length = 16;
+               if (len - i < 16) // Incomplete line.
+                       length = len - i;
+
+               // First, offsets.
+               if (format & PRINT_OFFSET) {
+
+                       fprintf(output, "%08x", i);
+
+                       if (format & USE_COLON)
+                               fprintf(output, ":");
+                       else if (format & PIPE_OFFSET)
+                               fprintf(output, " | ");
+                       else
+                               fprintf(output, " ");
+                       fprintf(output, " ");
+               }
+
+               // Next, bytes.
+               if (format & BYTE_A) { // One byte
+                       int copylen = length;
+                       for(int j=0; j < 16; j++) {
+                               if (copylen) {
+                                       fprintf(output, "%02x ", buffer[i+j]);
+                                       copylen--;
+                               } else {
+                                       fprintf(output, "   ");
+                               }
+                               if (j == 7 && (format & CENTER_SPLIT) )
+                                       fprintf(output, " ");
+                       }
+               } else if (format & BYTE_B) { // Two byte
+                       int copylen = length;
+                       for(int j=0; j < 16; j++) {
+                               if (copylen) {
+                                       fprintf(output, "%02x", buffer[i+j]);
+                                       if (j % 2 == 1)
+                                               fprintf(output, " ");
+                                       copylen--;
+                               } else {
+                                       fprintf(output, "  ");
+                                       if (j % 2 == 1)
+                                               fprintf(output, " ");
+                               }
+                               if (j == 7 && (format & CENTER_SPLIT) )
+                                       fprintf(output, " ");
+                       }
+               } else if (format & BYTE_C) { // Three byte
+                       int copylen = length;
+                       for(int j=0; j < 16; j++) {
+                               if (copylen) {
+                                       fprintf(output, "%02x", buffer[i+j]);
+                                       if (j % 4 == 3)
+                                               fprintf(output, " ");
+                                       copylen--;
+                               } else {
+                                       fprintf(output, "  ");
+                                       if (j % 4 == 3)
+                                               fprintf(output, " ");
+                               }
+                               if (j == 7 && (format & CENTER_SPLIT) )
+                                       fprintf(output, " ");
+                       }
+               }
+
+               if (format & WITH_ASCII) { // Print ascii
+                       fprintf(output, " ");
+
+                       if (format & PIPE_SEPARATE) {
+                               fprintf(output, "|");
+                       }
+
+                       for(int j=0; j < length; j++) {
+                               // We only print printables.
+                               int c = buffer[i+j];
+                               if (c > 0x1f && c < 0x7f) // Printable?
+                                       fprintf(output, "%c", c);
+                               else {
+                                       if (format & NONPRINT_PERIOD) {
+                                               fprintf(output, ".");
+                                       } else if (format & NONPRINT_UNDERS) {
+                                               fprintf(output, "_");
+                                       } else {
+                                               fprintf(output, " ");
+                                       }
+                               }
+                       }
+
+                       if (format & PIPE_SEPARATE) {
+                               fprintf(output, "|");
+                       }
+               }
+
+               i += 16;
+               fprintf(output, "\n");
+       }
+
+       return 0;
+}
+
+uint8_t hexb_to_u8(char a, char b) {
+       if (a >= 'a' && a <= 'f') {
+               a -= 'a';
+               a += 10;
+       } else if (a >= 'A' && a <= 'F') {
+               a -= 'A';
+               a += 10;
+       } else if (a >= '0' && a <= '9') {
+               a -= '0';
+       } else {
+               return 0;
+       }
+
+       if (b >= 'a' && b <= 'f') {
+               b -= 'a';
+               b += 10;
+       } else if (b >= 'A' && b <= 'F') {
+               b -= 'A';
+               b += 10;
+       } else if (b >= '0' && b <= '9') {
+               b -= '0';
+       } else {
+               return 0;
+       }
+
+       return ((a<<4)|b);
+}
+
+// Unhexdump
+int unhexdump_buffer(__READ uint8_t* buffer, __READ uint64_t len, __WRITE uint8_t* output) {
+       for(uint64_t i=0; i < (len/2); i++) {
+               output[i] = hexb_to_u8(buffer[i*2], buffer[i*2+1]);
+       }
+
+       return 0;
+}
diff --git a/host/ips2pco/blib.h b/host/ips2pco/blib.h
new file mode 100755 (executable)
index 0000000..b7f47b3
--- /dev/null
@@ -0,0 +1,79 @@
+/* Common functions for binary modifying programs. */
+
+#ifndef __BINLIB_H
+#define __BINLIB_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <unistd.h>
+
+#include "util.h"
+
+#ifdef MAX
+#undef MAX
+#endif
+#define MAX(a,b) \
+  ({ __typeof__ (a) _a = (a); \
+     __typeof__ (b) _b = (b); \
+     _a > _b ? _a : _b; })
+
+// map_file flags
+#define READ_FILE  0
+#define WRITE_FILE 1 // Implies read
+
+// Hexdump feature bits
+#define USE_SPACES      1
+#define PRINT_OFFSET    2
+#define USE_COLON       4
+#define LINE_BREAKS     8
+#define PIPE_SEPARATE   16
+#define PIPE_OFFSET     32
+#define WITH_ASCII      64
+#define BYTE_A          128  // 1byte
+#define BYTE_B          256  // 2byte
+#define BYTE_C          512  // 4byte
+#define CENTER_SPLIT    1024
+#define NONPRINT_PERIOD 2048
+#define NONPRINT_UNDERS 4096
+#define COLORIZED       8192
+
+// Hexdump presets.
+#define SPACED_BYTES       USE_SPACES | BYTE_A
+#define PRESET_XXD         USE_SPACES | BYTE_B | PRINT_OFFSET | USE_COLON | WITH_ASCII | LINE_BREAKS | NONPRINT_PERIOD
+#define PRESET_HEXDUMP_C   USE_SPACES | BYTE_A | PRINT_OFFSET | PIPE_SEPARATE | WITH_ASCII | LINE_BREAKS | CENTER_SPLIT | NONPRINT_PERIOD
+#define PRESET_FANCY       USE_SPACES | BYTE_A | PRINT_OFFSET | PIPE_SEPARATE | WITH_ASCII | LINE_BREAKS | CENTER_SPLIT | PIPE_OFFSET
+
+// None of these have any meaning, but serve as documentation.
+#ifdef NO_STRICT_SPECS
+  #define __READ
+#else
+  #define __READ const
+#endif
+
+#define __WRITE
+#define __WRITEREAD
+
+// Buffer size.
+#define BUFFER_SIZE 1024
+
+// Copy file.
+int copy_file(__READ char* dest, __READ char* src);
+
+// Hexdump
+int hexdump_file(__READ uint8_t *buffer, __READ uint64_t len, __READ int format);
+int hexdump_manual(__READ uint64_t offset, __READ uint8_t* buffer, __READ uint64_t len, __READ int format, FILE* output);
+
+// Unhexdump
+int unhexdump_buffer(__READ uint8_t* buffer, __READ uint64_t len, __WRITE uint8_t* output);
+
+#endif
diff --git a/host/ips2pco/ips_fmt.h b/host/ips2pco/ips_fmt.h
new file mode 100755 (executable)
index 0000000..cfd736a
--- /dev/null
@@ -0,0 +1,64 @@
+/* IPS. Pretty standard stuff. */
+
+#define IPS_MAGIC       "PATCH" // Original Spec
+#define IPS_MAGIC_LENGTH 5
+
+#define IPS_TAIL         "EOF"
+#define IPS_TAIL_LENGTH  3
+
+typedef struct ips_record_com_s {
+       uint8_t offset[3];
+       uint8_t size[2];
+} ips_record_com_t;
+
+typedef struct ips_record_rle_s {
+       uint8_t  rle_size[2];
+       uint8_t  byte;
+} ips_record_rle_t;
+
+typedef struct ips_record_s {
+       ips_record_com_t* info;
+       void* data; // Can be ips_record_rle_t or uint8_t.
+} ips_record_t;
+
+/* IPS32 is IPS with 32-bit offsets. */
+
+#define IPS32_MAGIC        "IPS32" // 32-bit extension
+#define IPS32_MAGIC_LENGTH 5
+
+#define IPS32_TAIL         "EEOF"
+#define IPS32_TAIL_LENGTH  4
+
+typedef struct ips32_record_com_s {
+       uint8_t offset[4];
+       uint8_t size[2];
+} ips32_record_com_t;
+
+typedef struct ips32_record_rle_s {
+       uint8_t  rle_size[2];
+       uint8_t  byte;
+} ips32_record_rle_t;
+
+typedef struct ips32_record_s {
+       ips32_record_com_t* info;
+       void* data; // Can be ips_record_rle_t or uint8_t.
+} ips32_record_t;
+
+#define TYPE_INVALID 0
+#define TYPE_IPS     1
+#define TYPE_IPS32   2
+
+#define BYTE4_TO_UINT32(bp) \
+     (((uint32_t)(bp [0]) << 24) & 0xFF000000) | \
+     (((uint32_t)(bp [1]) << 16) & 0x00FF0000) | \
+     (((uint32_t)(bp [2]) << 8 ) & 0x0000FF00) | \
+     ( (uint32_t)(bp [3])        & 0x000000FF)
+
+#define BYTE3_TO_UINT32(bp) \
+     (((uint32_t)(bp [0]) << 16) & 0x00FF0000) | \
+     (((uint32_t)(bp [1]) << 8 ) & 0x0000FF00) | \
+     ( (uint32_t)(bp [2])        & 0x000000FF)
+
+#define BYTE2_TO_UINT16(bp) \
+     (((uint16_t)(bp [0]) << 8 ) & 0xFF00) | \
+     ( (uint16_t)(bp [1])        & 0x00FF)
diff --git a/host/ips2pco/util.c b/host/ips2pco/util.c
new file mode 100755 (executable)
index 0000000..f0760b7
--- /dev/null
@@ -0,0 +1,97 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "blib.h"
+
+size_t fsize(FILE* file) {
+       size_t at = ftell(file);
+
+       fseek(file, 0, SEEK_END);
+       size_t size = ftell(file);
+       fseek(file, at, SEEK_SET);
+
+       return size;
+}
+
+int read_alloc_file(const char* filename, void** ptr, size_t* size) {
+       FILE* handle   = fopen(filename, "rb");
+       if (!handle)
+               return -READALLOC_NOFILE;
+       
+       size_t alloc_size = *size;
+
+       *size = fsize(handle);
+       if (size <= 0) {
+               fclose(handle);
+               *size = 0;
+               return -READALLOC_BADSIZE;
+       }
+       
+       if (alloc_size) {
+               *ptr = malloc(alloc_size);
+               if (alloc_size < *size) {
+                       *size = alloc_size;
+               }
+       } else {
+               *ptr = malloc(*size);
+       }
+
+       if (*ptr == NULL) {
+               fclose(handle);
+               *ptr = NULL;
+               *size = 0;
+               return -READALLOC_OOM;
+       }
+       
+       if (fread(*ptr, 1, *size, handle) != *size) {
+               free(*ptr);
+               fclose(handle);
+               *ptr = NULL;
+               *size = 0;
+               return -READALLOC_READERR;
+       }
+       
+       if (alloc_size && alloc_size > *size) {
+               *size = alloc_size;
+       }
+       
+       fclose(handle);
+       
+       return 0;
+}
+
+#define ALPHABET_LEN 256
+#define NOT_FOUND patlen
+#define max(a, b) ((a < b) ? b : a)
+
+// Quick Search algorithm, adapted from
+// http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
+const void *
+memfind(const void *input, uint32_t size, const void *pattern, uint32_t patternSize)
+{
+    const uint8_t *startPos = (const uint8_t *)input;
+    const uint8_t *patternc = (const uint8_t *)pattern;
+
+    // Preprocessing
+    uint32_t table[ALPHABET_LEN];
+
+    for (uint32_t i = 0; i < ALPHABET_LEN; ++i)
+        table[i] = patternSize + 1;
+    for (uint32_t i = 0; i < patternSize; ++i)
+        table[patternc[i]] = patternSize - i;
+
+    // Searching
+    size_t j = 0;
+
+    while (j <= size - patternSize) {
+        if (memcmp(patternc, startPos + j, patternSize) == 0)
+            return startPos + j;
+        j += table[startPos[j + patternSize]];
+    }
+
+    return NULL;
+}
+
diff --git a/host/ips2pco/util.h b/host/ips2pco/util.h
new file mode 100755 (executable)
index 0000000..2c0a443
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __LIBC2PATCHER_OLDVM_UTIL__
+#define __LIBC2PATCHER_OLDVM_UTIL__
+
+size_t fsize(FILE* file);
+
+const void* memfind(const void *input, uint32_t size, const void *pattern, uint32_t patternSize);
+
+#define READALLOC_NOFILE  1
+#define READALLOC_BADSIZE 2
+#define READALLOC_OOM     3
+#define READALLOC_READERR 4
+
+int read_alloc_file(const char* filename, void** ptr, size_t* size);
+
+#endif