Last active
August 29, 2015 14:04
-
-
Save majorpakhom/9804b2253cd69c4f4194 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Version 8. | |
Batch processing included. | |
listpatch <hex file> <binary file 1> ... <binary file N> | |
Naive, with optimizations: | |
compile with following options: | |
gcc -o listpatch listpatch.c -O3 -fexpensive-optimizations -fomit-frame-pointer | |
========== | |
Copyright (c) 2014 Major Pakhom <[email protected]> | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <time.h> | |
#define SFS_BUFFER_INIT_SIZE 16384 | |
#define SFS_MAX_BUFFER_SIZE 32*1024*1024 | |
#define TRUE 1 | |
#define FALSE 0 | |
typedef struct _string_list_entry string_list_entry; | |
typedef struct _string_list_entry { | |
char *string; | |
int length; | |
char *to; | |
int to_l; | |
string_list_entry *next; | |
} string_list_entry; | |
typedef struct _string_list { | |
string_list_entry root; | |
} string_list; | |
string_list_entry *string_list_last(string_list *sl) { | |
string_list_entry *e = &(sl->root); | |
while(e->next != NULL) { | |
e = e->next; | |
} | |
return e; | |
} | |
void string_list_create(string_list *sl) { | |
memset(sl, 0, sizeof(string_list)); | |
} | |
int string_list_check(string_list *sl, char *string, int length) { | |
string_list_entry *c = (&(sl->root))->next; | |
while(c != NULL) { | |
if(strcmp(string, c->string) == 0) { | |
return 1; | |
} | |
c = c->next; | |
} | |
return 0; | |
} | |
void string_list_add_entry(string_list *sl, char *string, int length, char *to, int to_l) { | |
if(!string_list_check(sl, string, length)) { | |
string_list_entry *e = (string_list_entry*) malloc(sizeof(string_list_entry)); | |
memset(e, 0, sizeof(string_list_entry)); | |
e->length = length; | |
e->string = (char*) malloc(length+1); | |
memcpy(e->string, string, length+1); | |
e->to_l = to_l; | |
e->to = (char*) malloc(to_l+1); | |
memcpy(e->to, to, to_l+1); | |
string_list_entry *l = string_list_last(sl); | |
l->next = e; | |
} | |
} | |
void sfs_zero(void *b, size_t c); | |
void sfs_copy(void *dest, void *src, int len); | |
typedef struct sfs_buffer { | |
int buff_size; | |
int length; | |
char *data; | |
} sfs_buffer; | |
int sfs_buffer_init(sfs_buffer *b) { | |
sfs_zero(b, sizeof(sfs_buffer)); | |
if((b->data = (char*) malloc(SFS_BUFFER_INIT_SIZE)) == NULL) { | |
return FALSE; | |
} | |
b->buff_size = SFS_BUFFER_INIT_SIZE; | |
return TRUE; | |
} | |
void sfs_buffer_free(sfs_buffer *b) { | |
free(b->data); | |
sfs_zero(b, sizeof(sfs_buffer)); | |
} | |
/* | |
Appends 'data' to the end of buffer 'b'. | |
*/ | |
int sfs_buffer_append(sfs_buffer *b, char *data, int len) { | |
if((b->length + len + 1) > b->buff_size) { | |
int new_size = b->buff_size * 2; | |
if(new_size >= SFS_MAX_BUFFER_SIZE) { | |
return FALSE; | |
} | |
char *new_data = (char*) realloc(b->data, new_size); | |
if(new_data == NULL) { | |
return FALSE; | |
} | |
b->data = new_data; | |
b->buff_size = new_size; | |
} | |
sfs_copy(b->data + b->length, data, len); | |
b->length = b->length + len; | |
b->data[b->length] = 0; | |
return TRUE; | |
} | |
static int _sfs_user_read_file(sfs_buffer *o, char *path) { | |
int read; | |
char buffer[512]; | |
FILE *f; | |
if((f = fopen(path, "rb")) == NULL) { | |
return FALSE; | |
} | |
while((read = fread(buffer, 1, 512, f)) != 0) { | |
if(!sfs_buffer_append(o, buffer, read)) { | |
fclose(f); | |
return FALSE; | |
} | |
} | |
fclose(f); | |
return TRUE; | |
} | |
static const char _hex_table[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; | |
static inline int _hex_proc_bits(int c) { | |
if((c >= 'a') && (c <= 'f')) { | |
c = c - 32; // lowercase to uppercase, see ASCII table for details | |
return (c-65)+10; | |
} | |
if((c >= '0') && (c <= '9')) { | |
return c - 48; | |
} else if((c >= 'A') && (c <= 'F')) { | |
return (c - 65) + 10; | |
} else { | |
return -1; | |
} | |
} | |
void sfs_zero(void *b, size_t c) { | |
memset(b, 0, c); | |
} | |
void sfs_copy(void *dest, void *src, int len) { | |
memcpy(dest, src, len); | |
} | |
int sfs_hex_to_string(char *out, char *in, int in_len) { | |
if(in_len%2 != 0) return -1; | |
int i; | |
int hb,lb; | |
for(i = 0; i < in_len/2; ++i) { | |
if((hb = _hex_proc_bits(in[i*2+0])) == -1) return -1; | |
if((lb = _hex_proc_bits(in[i*2+1])) == -1) return -1; | |
out[i] = ((hb << 4) & 0xF0) | (lb & 0x0F); | |
} | |
out[in_len/2] = 0; | |
return in_len/2; | |
} | |
typedef struct lp_t_s { | |
int fl; | |
char from[1024]; | |
int tl; | |
char to[1024]; | |
} lp_t; | |
const char *_bstrchr(const char *s, int c, size_t l); | |
const char *_bstrstr(const char *s1, size_t l1, const char *s2, size_t l2) { | |
/* find first occurrence of s2[] in s1[] for length l1*/ | |
const char *ss1 = s1; | |
const char *ss2 = s2; | |
/* handle special case */ | |
if (l1 == 0) | |
return (NULL); | |
if (l2 == 0) | |
return ((char *)s1); | |
/* match prefix */ | |
for (; (s1 = _bstrchr(s1, *s2, ss1-s1+l1)) != NULL && ss1-s1+l1!=0; ++s1) { | |
/* match rest of prefix */ | |
const char *sc1, *sc2; | |
for (sc1 = s1, sc2 = s2; ;) | |
if (++sc2 >= ss2+l2) | |
return ((char *)s1); | |
else if (*++sc1 != *sc2) | |
break; | |
} | |
return (NULL); | |
} | |
const char *_bstrchr(const char *s, int c, size_t l) { | |
/* find first occurrence of c in char s[] for length l*/ | |
const char ch = c; | |
/* handle special case */ | |
if (l == 0) | |
return (NULL); | |
for (; *s != ch; ++s, --l) | |
if (l == 0) | |
return (NULL); | |
return ((char*)s); | |
} | |
char from_b[4096]; | |
char to_b[4096]; | |
int hex_f_l = 0; | |
int hex_t_l = 0; | |
int changes_count = 0; | |
lp_t changes; | |
int rb_length = 0; | |
char *rb; | |
int hb_l; | |
char hb[4096]; | |
// listpatch change.hex <input 1> ... <input N> | |
/* Reads a binary file and a list of replacements in HEX format, as: | |
ABCD:1234 | |
FFFF:0000 | |
where prefix is string to look for, and postfix is a string to replace it to. | |
*/ | |
char *hex_file = NULL; | |
char *in_file = NULL; | |
typedef struct file_t { | |
char name[256]; | |
sfs_buffer data; | |
} file_t; | |
int files_count = 0; | |
file_t *files; | |
int main(int argc, char ** argv) { | |
hex_file = argv[1]; | |
files = (file_t *) malloc(sizeof(file_t)*4096); | |
memset(files, 0, sizeof(file_t)*4096); | |
string_list slst; | |
string_list_create(&slst); | |
int i; | |
for(i = 2; i < argc; ++i) { | |
printf("Processing %d.\n", i); | |
fflush(stdout); | |
file_t *cf = &files[files_count]; | |
memset(cf, 0, sizeof(file_t)); | |
memcpy(cf->name, argv[i], strlen(argv[i])+1); | |
if(!sfs_buffer_init(&cf->data)) { | |
printf("Failed to init file %s.\n", argv[i]); | |
return -1; | |
} | |
if(!_sfs_user_read_file(&cf->data, cf->name)) { | |
printf("Failed to read file %s.\n", argv[i]); | |
return -1; | |
} | |
++files_count; | |
} | |
time_t start_time = clock(); | |
FILE *f = fopen(hex_file, "r"); | |
int lines_processed = 1, occurences = 0; | |
while(fgets(hb, 4096, f) != NULL) { | |
int len = strlen(hb); | |
int offset = strstr(hb, ":")-hb; | |
if(offset == -1) continue; | |
memcpy(from_b, hb, offset); | |
from_b[offset] = 0; | |
memcpy(to_b, hb+offset+1, len-(offset)); | |
to_b[len-(offset+1)] = 0; | |
changes.fl = sfs_hex_to_string(changes.from, from_b, offset); | |
changes.tl = sfs_hex_to_string(changes.to, to_b, len-(offset+2)); | |
char *off_bytes = NULL; | |
int j; | |
for(j = 0; j < files_count; ++j) { | |
while((off_bytes = (char*)_bstrstr(files[j].data.data, files[j].data.length, changes.from, changes.fl)) != NULL) { | |
memcpy(off_bytes, changes.to, changes.tl); | |
occurences++; | |
string_list_add_entry(&slst, from_b, offset, to_b, len-(offset+1)); | |
} | |
} | |
float lps = (float) 1000.0*lines_processed/((float) clock()-start_time); | |
printf("Line #%d; %.2f lps; %d rp; %.2f rpps\n", lines_processed, lps, occurences, 1000.0*occurences/((float) clock()-start_time)); | |
++lines_processed; | |
} | |
fclose(f); | |
char fname[128]; | |
FILE *o; | |
for(i = 0; i < files_count; ++i) { | |
sprintf(fname, "changed_%s", files[i].name); | |
o = fopen(fname, "wb"); | |
if(o == NULL) { | |
printf("Failed to write %s.\n", fname); | |
continue; | |
} | |
fwrite(files[i].data.data, 1, files[i].data.length, o); | |
fclose(o); | |
} | |
o = fopen("_DONE.txt", "w"); | |
string_list_entry *e = &(slst.root); | |
while((e = e->next) != NULL) { | |
fprintf(o, "%s:%s", e->string, e->to); | |
} | |
fclose(o); | |
printf("Processed %d files successfully in %.3fs.\n", files_count, ((int) (clock()-start_time))/1000.0); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment