Skip to content

Commit

Permalink
th06 asking for PNG files with indexed coulors was not due to th06 ne…
Browse files Browse the repository at this point in the history
…eding PNG files with indexed coulors, but to a buffer overflow check that wasn't covered by BP_size, in the PNG parsing function (see thcrap-tsa/4be5e0b). That means all this stuff about creating PNG files with indexed coulors was useless ; th06 supports regular RGB PNG files everywhere. And since this stuff is quite heavy on CPU and degrades the image to reduce it to 256 colors, we'd better remove it.
  • Loading branch information
brliron committed Apr 14, 2016
1 parent bd24873 commit 940da5b
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 267 deletions.
12 changes: 2 additions & 10 deletions thcrap_tsa/src/th06_bp_file.c
Expand Up @@ -148,11 +148,7 @@ int BP_th06_file_loaded(x86_reg_t *regs, json_t *bp_info)
// Compute the alpha mask
log_print("(PNG) Computing alpha mask\n");
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);
}
dst = pngsplit_create_png_mask(pngsplit_png);
if (!dst) {
log_print("(PNG) Error\n");
PNGSPLIT_SAFE_FREE(pngsplit_png);
Expand Down Expand Up @@ -190,11 +186,7 @@ int BP_th06_file_loaded(x86_reg_t *regs, json_t *bp_info)

log_print("(PNG) Computing indexed image\n");
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);
}
dst = pngsplit_create_rgb_file(pngsplit_png);
if (!dst) {
log_print("(PNG) Error\n");
PNGSPLIT_SAFE_FREE(pngsplit_png);
Expand Down
257 changes: 0 additions & 257 deletions thcrap_tsa/src/th06_pngsplit.c
Expand Up @@ -24,8 +24,6 @@ typedef struct {
png_structp png;
png_infop info;
png_uint_32 width, height;
png_colorp plt;
int plt_size;
png_bytep data;
png_bytepp row_pointers;
} pngsplit_png_t;
Expand Down Expand Up @@ -87,7 +85,6 @@ void pngsplit_free(pngsplit_png_t *png)
if (png) {
SAFE_FREE(png->data);
SAFE_FREE(png->row_pointers);
SAFE_FREE(png->plt);

if (png->png) {
if (png->alloc_type == PNGSPLIT_ALLOC_READ) {
Expand Down Expand Up @@ -189,9 +186,6 @@ 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);

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

png_write_image(png->png, png->row_pointers);
Expand All @@ -206,59 +200,6 @@ void pngsplit_write(char *buff, pngsplit_png_t *png)



pngsplit_png_t *pngsplit_create_png_mask_plt(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,
4,
PNG_COLOR_TYPE_PALETTE,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);
out->plt = malloc(16 * sizeof(png_color));
out->plt_size = 16;
for (int i = 0; i < 16; i++) {
png_byte color = i + (i << 4);
out->plt[i].red = color;
out->plt[i].green = color;
out->plt[i].blue = color;
}

if (out->plt && 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]);
if (x % 2 == 0) {
out->row_pointers[y][x / 2] &= 0x0F;
out->row_pointers[y][x / 2] |= px[3] & 0xF0;
} else {
out->row_pointers[y][x / 2] &= 0xF0;
out->row_pointers[y][x / 2] |= px[3] >> 4;
}
}
}
err = 0;
}
}

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

return out;
}

pngsplit_png_t *pngsplit_create_png_mask(pngsplit_png_t *in)
{
int err = -1;
Expand Down Expand Up @@ -305,204 +246,6 @@ pngsplit_png_t *pngsplit_create_png_mask(pngsplit_png_t *in)



static png_uint_32 *build_palette(pngsplit_png_t *png, int *plt_size)
{
png_uint_32* plt = NULL;
int alloc_size = 0;
*plt_size = 0;

for (png_uint_32 y = 0; y < png->height; y++) {
png_uint_32* row = (png_uint_32*)png->row_pointers[y];
for (png_uint_32 x = 0; x < png->width; x++) {
png_uint_32 px = row[x]; // px is in RGBA BE format.
px &= 0x00FFFFFF; // Removing alpha

int i;
for (i = 0; i < *plt_size; i++) {
if (plt[i] == px) {
break;
}
}
if (i == *plt_size) {
if (i == alloc_size) {
if (alloc_size == 0) {
alloc_size = 256;
} else {
alloc_size <<= 1;
}
plt = realloc(plt, alloc_size * sizeof(png_uint_32));
if (plt == NULL) {
return NULL;
}
}
plt[i] = px;
(*plt_size)++;
}
}
}
return plt;
}

static png_uint_32 *build_assoc_table(png_uint_32 *plt, int plt_size, int *assoc_table_size)
{
if (plt == NULL) {
return NULL;
}

png_uint_32 *assoc_table = malloc(plt_size * 2 * sizeof(png_uint_32));
if (assoc_table == NULL) {
return NULL;
}
*assoc_table_size = 0;
int nb_colors = plt_size, shift = 1;

while (nb_colors > 256) {
for (int i = 0; i < plt_size; i++) {
png_bytep px1 = (png_bytep)(plt + i);
if (px1[3] == 0xFF) {
continue;
}
for (int j = i + 1; j < plt_size; j++) {
png_bytep px2 = (png_bytep)(plt + j);
if (px2[3] != 0xFF && ABS(px1[0] - px2[0]) + ABS(px1[1] - px2[1]) + ABS(px1[2] - px2[2]) <= shift) {
assoc_table[*assoc_table_size] = plt[j];
assoc_table[*assoc_table_size + 1] = plt[i];
(*assoc_table_size) += 2;
px2[3] = 0xFF;
nb_colors--;
}
}
}
shift++;
}
return assoc_table;
}

static void sort_assoc_table(png_uint_32 *assoc, int assoc_size)
{
for (int i = 2; i < assoc_size; ) {
if (assoc[i - 2] > assoc[i]) {
png_uint_32 tmp;
tmp = assoc[i - 2];
assoc[i - 2] = assoc[i];
assoc[i] = tmp;
tmp = assoc[i - 1];
assoc[i - 1] = assoc[i + 1];
assoc[i + 1] = tmp;
if (i != 2)
i -= 2;
}
else
i += 2;
}
}

static UINT32 get_assoc(UINT32 px, UINT32* assoc_table, int assoc_table_size)
{
int min, max, mid;
UINT32 cur;

min = 0;
max = assoc_table_size / 2 - 1;
while (1)
{
if (max - min < 10)
{
for (int i = min; i <= max; i++)
if (assoc_table[i * 2] == px)
{
px = assoc_table[i * 2 + 1];
return get_assoc(assoc_table[i * 2 + 1], assoc_table, assoc_table_size);
}
return px;
}
mid = (max - min) / 2 + min;
cur = assoc_table[mid * 2];
if (cur == px)
return get_assoc(assoc_table[mid * 2 + 1], assoc_table, assoc_table_size);
else if (cur < px)
min = mid;
else if (cur > px)
max = mid;
}
}

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;
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_PALETTE,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);

plt = build_palette(in, &plt_size);
assoc_table = build_assoc_table(plt, plt_size, &assoc_table_size);
sort_assoc_table(assoc_table, assoc_table_size);

out->plt = malloc(plt_size * sizeof(png_color));
out->plt_size = 0;
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);
out->plt[out->plt_size].red = px[0];
out->plt[out->plt_size].green = px[1];
out->plt[out->plt_size].blue = px[2];
out->plt_size++;
}
}

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++) {
png_uint_32 px = row[x]; // px is in RGBA BE format.
px &= 0x00FFFFFF; // Remove alpha
px = get_assoc(px, assoc_table, assoc_table_size);

png_bytep px_ptr = (png_bytep)&px;
int idx;
for (idx = 0; idx < out->plt_size; idx++) {
if (px_ptr[0] == out->plt[idx].red && px_ptr[1] == out->plt[idx].green && px_ptr[2] == out->plt[idx].blue) {
break;
}
}
if (idx == out->plt_size) {
printf("Error in pngsplit: color %X not found in palette. Defaulting to index 0.\n", px);
idx = 0;
}
out->row_pointers[y][x] = idx;
}
}
err = 0;
}
}

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

return out;
}

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

0 comments on commit 940da5b

Please sign in to comment.