Skip to content

Commit

Permalink
th06: add support for patching of 24-bits RGB files
Browse files Browse the repository at this point in the history
  • Loading branch information
brliron committed Mar 26, 2016
1 parent c1634ad commit 5bf74d6
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 16 deletions.
44 changes: 35 additions & 9 deletions thcrap_tsa/src/th06_bp_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ typedef enum {
} th06_pngsplit_t;

// Maximum size of the generated image.
const pngsplit_max_image_size =
const size_t pngsplit_max_image_size =
8 // Magic
+ 12 + 13 // IDHR
+ 12 + 3 * 256 // PLTE
+ 12 + 257 * 256 // IDAT
+ 12 + 257 * 256 * 3 // IDAT
+ 12; // IEND

th06_pngsplit_t pngsplit_state;
Expand Down Expand Up @@ -66,11 +66,16 @@ int BP_th06_file_size(x86_reg_t *regs, json_t *bp_info)
{
if (pngsplit_state != TH06_PNGSPLIT_NONE) {
// Ensure we'll have enough space for the patched PNG file
int *file_size = (int*)json_object_get_register(bp_info, regs, "file_size");
size_t *file_size = (size_t*)json_object_get_register(bp_info, regs, "file_size");
file_rep_t *fr = fr_tls_get();

if (*file_size < pngsplit_max_image_size) {
*file_size = pngsplit_max_image_size;
}
if (*file_size < fr->pre_json_size) {
*file_size = fr->pre_json_size;
}
return 1;
}
return BP_file_size(regs, bp_info);
}
Expand Down Expand Up @@ -131,17 +136,31 @@ int BP_th06_file_loaded(x86_reg_t *regs, json_t *bp_info)
return BP_file_loaded(regs, bp_info);
}

// If the original PNG doesn't use a palette, the game's PNG parser will handle any PNG file.
if (((png_bytep)fr->game_buffer)[8 /* magic */ + 8 /* chunk header */ + 9 /* index of color type in IHRD */] != PNG_COLOR_TYPE_PALETTE) {
png_byte orig_bit_depth = ((png_bytep)fr->game_buffer)[8 /* magic */ + 8 /* chunk header */ + 8 /* index of bit depth in IHRD */];
png_byte orig_color_type = ((png_bytep)fr->game_buffer)[8 /* magic */ + 8 /* chunk header */ + 9 /* index of color type in IHRD */];
if (orig_color_type != PNG_COLOR_TYPE_RGB && orig_color_type != PNG_COLOR_TYPE_PALETTE) { // I don't think the game uses another color type. Maybe RGBA, and in that case the input file will probably be RGBA as well.
return th06_skip_image(fr);
}

if (pngsplit_state == TH06_PNGSPLIT_ALPHA) {
if (((png_bytep)fr->game_buffer)[8 /* magic */ + 8 /* chunk header */ + 8 /* index of bit depth in IHRD */] == 4) {
if (fr->name && strlen(fr->name) >= 6 &&
!strcmp(fr->name + strlen(fr->name) - 6, "_a.png")) {
// Compute the alpha mask
log_print("(PNG) Computing alpha mask\n");
void *dst = pngsplit_create_png_mask(pngsplit_png);
void *dst;
if (orig_color_type == PNG_COLOR_TYPE_PALETTE) {
dst = pngsplit_create_png_mask_plt(pngsplit_png);
} else {
dst = pngsplit_create_png_mask(pngsplit_png);
}
if (!dst) {
log_print("(PNG) Error\n");
PNGSPLIT_SAFE_FREE(pngsplit_png);
pngsplit_state = TH06_PNGSPLIT_NONE;
return BP_file_loaded(regs, bp_info);
}
pngsplit_write(fr->game_buffer, dst);
dst = NULL;

PNGSPLIT_SAFE_FREE(pngsplit_png);
pngsplit_state = TH06_PNGSPLIT_NONE;
Expand All @@ -156,7 +175,7 @@ int BP_th06_file_loaded(x86_reg_t *regs, json_t *bp_info)
if (pngsplit_state == TH06_PNGSPLIT_RGB)
{
// If we have an alpha mask here, that means the patch developer tries to replace the image for the alpha mask, and... let's hope he knows what he does.
if (((png_bytep)fr->game_buffer)[8 /* magic */ + 8 /* chunk header */ + 8 /* index of bit depth in IHRD */] != 8) {
if (orig_color_type == PNG_COLOR_TYPE_PALETTE && orig_bit_depth != 8) {
return th06_skip_image(fr);
}

Expand All @@ -168,15 +187,22 @@ int BP_th06_file_loaded(x86_reg_t *regs, json_t *bp_info)
return BP_file_loaded(regs, bp_info);
}


log_print("(PNG) Computing indexed image\n");
void* dst = pngsplit_create_rgb_file(pngsplit_png);
void* dst;
if (orig_color_type == PNG_COLOR_TYPE_PALETTE) {
dst = pngsplit_create_rgb_file_plt(pngsplit_png);
} else {
dst = pngsplit_create_rgb_file(pngsplit_png);
}
if (!dst) {
log_print("(PNG) Error\n");
PNGSPLIT_SAFE_FREE(pngsplit_png);
pngsplit_state = TH06_PNGSPLIT_NONE;
return BP_file_loaded(regs, bp_info);
}
pngsplit_write(fr->game_buffer, dst);
dst = NULL;

file_rep_clear(fr);
pngsplit_state = TH06_PNGSPLIT_ALPHA;
Expand Down
98 changes: 91 additions & 7 deletions thcrap_tsa/src/th06_pngsplit.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ void pngsplit_free(pngsplit_png_t *png)




void pngsplit_read_callback(png_struct *png, png_bytep out, png_uint_32 len)
{
pngsplit_io_t *io = png_get_io_ptr(png);
Expand Down Expand Up @@ -190,10 +189,11 @@ void pngsplit_write(char *buff, pngsplit_png_t *png)
io.pos = 0;
png_set_write_fn(png->png, &io, pngsplit_write_callback, pngsplit_write_flush_callback);

png_set_PLTE(png->png, png->info, png->plt, png->plt_size);
if (png->plt) {
png_set_PLTE(png->png, png->info, png->plt, png->plt_size);
}
png_write_info(png->png, png->info);

png_set_compression_level(png->png, 9);
png_write_image(png->png, png->row_pointers);
png_write_end(png->png, NULL);
}
Expand All @@ -206,7 +206,7 @@ void pngsplit_write(char *buff, pngsplit_png_t *png)



pngsplit_png_t *pngsplit_create_png_mask(pngsplit_png_t *in)
pngsplit_png_t *pngsplit_create_png_mask_plt(pngsplit_png_t *in)
{
int err = -1;

Expand Down Expand Up @@ -259,6 +259,47 @@ pngsplit_png_t *pngsplit_create_png_mask(pngsplit_png_t *in)
return out;
}

pngsplit_png_t *pngsplit_create_png_mask(pngsplit_png_t *in)
{
int err = -1;

pngsplit_png_t *out = pngsplit_alloc(PNGSPLIT_ALLOC_WRITE);
if (!out)
return NULL;
if (!setjmp(png_jmpbuf(out->png))) {
out->width = in->width; out->height = in->height;
png_set_IHDR(out->png,
out->info,
out->width, out->height,
8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);

if (pngsplit_alloc_data(out) != -1) {
for (png_uint_32 y = 0; y < in->height; y++) {
png_bytep row = in->row_pointers[y];
for (png_uint_32 x = 0; x < in->width; x++) {
png_bytep px = &(row[x * 4]);
out->row_pointers[y][x * 3 + 0] = px[3];
out->row_pointers[y][x * 3 + 1] = px[3];
out->row_pointers[y][x * 3 + 2] = px[3];
}
}
err = 0;
}
}

if (err == -1) {
pngsplit_free(out);
out = NULL;
}

return out;
}




Expand Down Expand Up @@ -386,7 +427,7 @@ static UINT32 get_assoc(UINT32 px, UINT32* assoc_table, int assoc_table_size)
}
}

pngsplit_png_t *pngsplit_create_rgb_file(pngsplit_png_t *in)
pngsplit_png_t *pngsplit_create_rgb_file_plt(pngsplit_png_t *in)
{
png_uint_32 *plt = NULL, *assoc_table = NULL;
int plt_size, assoc_table_size;
Expand Down Expand Up @@ -416,7 +457,7 @@ pngsplit_png_t *pngsplit_create_rgb_file(pngsplit_png_t *in)

out->plt = malloc(plt_size * sizeof(png_color));
out->plt_size = 0;
if (plt && assoc_table && out->plt) {
if (plt && assoc_table && out->plt && pngsplit_alloc_data(out) != -1) {
for (int i = 0; i < plt_size; i++) {
if ((plt[i] & 0xFF000000) == 0) {
png_bytep px = (png_bytep)(plt + i);
Expand All @@ -427,7 +468,6 @@ pngsplit_png_t *pngsplit_create_rgb_file(pngsplit_png_t *in)
}
}

pngsplit_alloc_data(out);
for (png_uint_32 y = 0; y < in->height; y++) {
png_uint_32 *row = (png_uint_32*)in->row_pointers[y];
for (png_uint_32 x = 0; x < in->width; x++) {
Expand Down Expand Up @@ -462,3 +502,47 @@ pngsplit_png_t *pngsplit_create_rgb_file(pngsplit_png_t *in)

return out;
}

pngsplit_png_t *pngsplit_create_rgb_file(pngsplit_png_t *in)
{
int err = -1;

pngsplit_png_t *out;
out = pngsplit_alloc(PNGSPLIT_ALLOC_WRITE);
if (out == NULL) {
return NULL;
}

if (!setjmp(png_jmpbuf(out->png))) {
out->width = in->width; out->height = in->height;
png_set_IHDR(out->png,
out->info,
out->width, out->height,
8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);

if (pngsplit_alloc_data(out) != -1) {
for (png_uint_32 y = 0; y < in->height; y++) {
png_bytep row = in->row_pointers[y];
for (png_uint_32 x = 0; x < in->width; x++) {
png_bytep px = &(row[x * 4]); // px is in RGBA BE format.
out->row_pointers[y][x * 3 + 0] = px[0];
out->row_pointers[y][x * 3 + 1] = px[1];
out->row_pointers[y][x * 3 + 2] = px[2];
}
}
err = 0;
}
}

if (err == -1) {
pngsplit_free(out);
out = NULL;
}

return out;
}
2 changes: 2 additions & 0 deletions thcrap_tsa/src/th06_pngsplit.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
void *pngsplit_read(void *buff);
void pngsplit_write(char *buff, void *png);

void *pngsplit_create_png_mask_plt(void *in);
void *pngsplit_create_png_mask(void *in);
void *pngsplit_create_rgb_file_plt(void *in);
void *pngsplit_create_rgb_file(void *in);

void pngsplit_free(void *png);

0 comments on commit 5bf74d6

Please # to comment.