From 2c3666a57253b578cbe62c984058fdfb0d1bc5bb Mon Sep 17 00:00:00 2001 From: Zoltan Baldaszti Date: Thu, 8 Dec 2022 00:50:59 +0100 Subject: [PATCH 1/4] Update xplode.c --- build/tools/xplode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/tools/xplode.c b/build/tools/xplode.c index 1e139945d..f2dc55e44 100644 --- a/build/tools/xplode.c +++ b/build/tools/xplode.c @@ -110,7 +110,7 @@ s32 main(s32 argc, char** argv) for(s32 i = 0; i < TIC80_WIDTH * TIC80_HEIGHT; i++) ((u32*)img.data)[i] = tic_rgba(&cart->bank0.palette.vbank0.colors[tic_tool_peek4(cart->bank0.screen.data, i)]); - png_buffer png = png_write(img); + png_buffer png = png_write(img, (png_buffer){NULL, 0}); writeFile("cover.png", (FileBuffer){png.size, png.data}); printf("cover.png successfully exported\n"); @@ -159,7 +159,7 @@ s32 main(s32 argc, char** argv) ((u32*)img.data)[x + y * TIC_SPRITESHEET_SIZE] = tic_rgba(&cart->bank0.palette.vbank0.colors[index]); } - png_buffer png = png_write(img); + png_buffer png = png_write(img, (png_buffer){NULL, 0}); writeFile("tiles.png", (FileBuffer){png.size, png.data}); printf("tiles.png successfully exported\n"); @@ -180,7 +180,7 @@ s32 main(s32 argc, char** argv) ((u32*)img.data)[x + y * TIC_SPRITESHEET_SIZE] = tic_rgba(&cart->bank0.palette.vbank0.colors[index]); } - png_buffer png = png_write(img); + png_buffer png = png_write(img, (png_buffer){NULL, 0}); writeFile("sprites.png", (FileBuffer){png.size, png.data}); printf("sprites.png successfully exported\n"); @@ -195,4 +195,4 @@ s32 main(s32 argc, char** argv) else printf("usage: xplode \n"); return 0; -} \ No newline at end of file +} From a67c4d6a5db320096b553401b73f0e2ff1aa457e Mon Sep 17 00:00:00 2001 From: Zoltan Baldaszti Date: Thu, 8 Dec 2022 00:51:48 +0100 Subject: [PATCH 2/4] Update console.c --- src/studio/screens/console.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/studio/screens/console.c b/src/studio/screens/console.c index 58d35228e..cc3dca270 100644 --- a/src/studio/screens/console.c +++ b/src/studio/screens/console.c @@ -1747,7 +1747,7 @@ static void onImportTilesBase(Console* console, const char* name, const void* bu png_buffer png = {(u8*)buffer, size}; bool error = true; - png_img img = png_read(png); + png_img img = png_read(png, NULL); if(img.data) SCOPE(free(img.data)) { @@ -1829,7 +1829,7 @@ static void onImport_screen(Console* console, const char* name, const void* buff png_buffer png = {(u8*)buffer, size}; bool error = true; - png_img img = png_read(png); + png_img img = png_read(png, NULL); if(img.data) SCOPE(free(img.data)) { @@ -1948,7 +1948,7 @@ static void exportSprites(Console* console, const char* filename, tic_tile* base for(s32 i = 0; i < TIC_SPRITESHEET_SIZE * TIC_SPRITESHEET_SIZE; i++) img.values[i] = tic_rgba(&pal->colors[getSpritePixel(base, i % TIC_SPRITESHEET_SIZE, i / TIC_SPRITESHEET_SIZE)]); - png_buffer png = png_write(img); + png_buffer png = png_write(img, (png_buffer){NULL, 0}); SCOPE(free(png.data)) { @@ -2258,7 +2258,7 @@ static void onExport_mapimg(Console* console, const char* param, const char* pat } } - png_buffer png = png_write(img); + png_buffer png = png_write(img, (png_buffer){NULL, 0}); SCOPE(free(png.data)) { @@ -2306,7 +2306,7 @@ static void onExport_screen(Console* console, const char* param, const char* nam for(s32 i = 0; i < TIC80_WIDTH * TIC80_HEIGHT; i++) img.values[i] = tic_rgba(&pal->colors[tic_tool_peek4(bank->screen.data, i)]); - png_buffer png = png_write(img); + png_buffer png = png_write(img, (png_buffer){NULL, 0}); SCOPE(free(png.data)) { @@ -2404,7 +2404,7 @@ static CartSaveResult saveCartName(Console* console, const char* name) }; png_buffer template = {(u8*)Cartridge, sizeof Cartridge}; - png_img img = png_read(template); + png_img img = png_read(template, NULL); // draw screen { @@ -2452,7 +2452,7 @@ static CartSaveResult saveCartName(Console* console, const char* name) ptr[CoverWidth * y + x] = tic_rgba(pal + tic_tool_peek4(screen, y * TIC80_WIDTH + x)); } - cover = png_write(img); + cover = png_write(img, (png_buffer){NULL, 0}); free(img.data); } From acd4e42b360c20e33c873d0631f316152c28efb1 Mon Sep 17 00:00:00 2001 From: Zoltan Baldaszti Date: Thu, 8 Dec 2022 00:52:30 +0100 Subject: [PATCH 3/4] Update png.h --- src/ext/png.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext/png.h b/src/ext/png.h index 930ab6236..bbd4746a3 100644 --- a/src/ext/png.h +++ b/src/ext/png.h @@ -60,8 +60,8 @@ typedef struct png_buffer png_create(s32 size); -png_img png_read(png_buffer buf); -png_buffer png_write(png_img src); +png_img png_read(png_buffer buf, png_buffer *cart); +png_buffer png_write(png_img src, png_buffer cart); png_buffer png_encode(png_buffer cover, png_buffer cart); png_buffer png_decode(png_buffer cover); From 78fc5ceb6892f00fb68201d3c87a5014b35c723f Mon Sep 17 00:00:00 2001 From: Zoltan Baldaszti Date: Thu, 8 Dec 2022 01:01:12 +0100 Subject: [PATCH 4/4] Update png.c --- src/ext/png.c | 57 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/src/ext/png.c b/src/ext/png.c index 62a952e80..ec07fa941 100644 --- a/src/ext/png.c +++ b/src/ext/png.c @@ -1,6 +1,7 @@ // MIT License // Copyright (c) 2021 Vadim Grigoruk @nesbox // grigoruk@gmail.com +// Copyright (c) 2022 bzt png chunk stuff // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,6 +29,7 @@ #include #include "tic_assert.h" +#define EXTRA_CHUNK "caRt" #define RGBA_SIZE sizeof(u32) png_buffer png_create(s32 size) @@ -48,7 +50,7 @@ static void pngReadCallback(png_structp png, png_bytep out, png_size_t size) stream->pos += size; } -png_img png_read(png_buffer buf) +png_img png_read(png_buffer buf, png_buffer *cart) { png_img res = { 0 }; @@ -102,6 +104,28 @@ png_img png_read(png_buffer buf) free(rows); + // Read in cartridge data from chunk if possible + if (cart) + { + png_unknown_chunkp unknowns = NULL; + int num_unknowns; + + png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, EXTRA_CHUNK, 1); + png_read_end(png, info); + num_unknowns = png_get_unknown_chunks(png, info, &unknowns); + for(s32 i = 0; i < num_unknowns; i++) + if (!memcmp(unknowns[i].name, EXTRA_CHUNK, 5)) + { + cart->size = unknowns[i].size; + cart->data = (u8*)malloc(cart->size); + if (cart->data) + memcpy(cart->data, unknowns[i].data, cart->size); + else + cart->size = 0; + break; + } + } + png_destroy_read_struct(&png, &info, NULL); } @@ -121,7 +145,7 @@ static void pngWriteCallback(png_structp png, png_bytep data, png_size_t size) static void pngFlushCallback(png_structp png) {} -png_buffer png_write(png_img src) +png_buffer png_write(png_img src, png_buffer cart) { png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info = png_create_info_struct(png); @@ -141,6 +165,17 @@ png_buffer png_write(png_img src) PNG_FILTER_TYPE_DEFAULT ); + // Save cartridge data in a chunk too. This supports bigger cartridges than steganography + if (cart.data && cart.size > 0 && cart.size <= 0x7fffff){ + png_unknown_chunk unknowns = { 0 }; + memcpy(&unknowns.name, EXTRA_CHUNK, 5); + unknowns.data = cart.data; + unknowns.size = cart.size; + unknowns.location = PNG_AFTER_IDAT; + png_set_unknown_chunks(png, info, &unknowns, 1); + png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, EXTRA_CHUNK, 1); + } + png_write_info(png, info); png_bytep* rows = malloc(sizeof(png_bytep) * src.height); @@ -148,7 +183,7 @@ png_buffer png_write(png_img src) rows[i] = src.data + src.width * i * RGBA_SIZE; png_write_image(png, rows); - png_write_end(png, NULL); + png_write_end(png, info); png_destroy_write_struct(&png, &info); @@ -189,7 +224,7 @@ static inline s32 ceildiv(s32 a, s32 b) png_buffer png_encode(png_buffer cover, png_buffer cart) { - png_img png = png_read(cover); + png_img png = png_read(cover, NULL); const s32 cartBits = cart.size * BITS_IN_BYTE; const s32 coverSize = png.width * png.height * RGBA_SIZE - HEADER_SIZE; @@ -206,7 +241,7 @@ png_buffer png_encode(png_buffer cover, png_buffer cart) for (s32 i = end; i < coverSize; i++) bitcpy(dst, i << 3, (const u8[]){rand()}, 0, header.bits); - png_buffer out = png_write(png); + png_buffer out = png_write(png, cart); free(png.data); @@ -215,8 +250,18 @@ png_buffer png_encode(png_buffer cover, png_buffer cart) png_buffer png_decode(png_buffer cover) { - png_img png = png_read(cover); + png_buffer cart = { 0 }; + png_img png = png_read(cover, &cart); + + // if we have a data from a png chunk, use that + if (cart.data && cart.size > 0) + { + if (png.data) + free(png.data); + return cart; + } + // otherwise fallback to steganography if (png.data) { Header header;