Skip to content

Commit

Permalink
Fixed a bug when memory allocation error occurred
Browse files Browse the repository at this point in the history
  • Loading branch information
nopnop2002 committed Dec 12, 2024
1 parent e71d4aa commit 1c4b847
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 108 deletions.
5 changes: 4 additions & 1 deletion main/decode_jpeg_v5.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ esp_err_t decode_jpeg(pixel_jpeg ***pixels, char * file, int screenWidth, int sc
JpegDev jd;
*pixels = NULL;
esp_err_t ret = ESP_OK;
jd.fp = NULL;

ESP_LOGW(__FUNCTION__, "v5 version. JPEG Decoder is %s", JPEG);
//Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines.
Expand Down Expand Up @@ -184,14 +185,16 @@ esp_err_t decode_jpeg(pixel_jpeg ***pixels, char * file, int screenWidth, int sc

//Something went wrong! Exit cleanly, de-allocating everything we allocated.
err:
fclose(jd.fp);
ESP_LOGD(__FUNCTION__, "start err");
if (*pixels != NULL) {
for (int i = 0; i < screenHeight; i++) {
if ((*pixels)[i]) free((*pixels)[i]);
}
free(*pixels);
}
free(work);
if (jd.fp) fclose(jd.fp);
ESP_LOGD(__FUNCTION__, "done err");
return ret;
}

Expand Down
7 changes: 6 additions & 1 deletion main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ TickType_t PNGTest(TFT_t * dev, char * file, int width, int height) {

pngle_t *pngle = pngle_new(_width, _height);
if (pngle == NULL) {
ESP_LOGE(__FUNCTION__, "pngle_new fail");
fclose(fp);
return 0;
}
Expand Down Expand Up @@ -1046,6 +1047,11 @@ void ShowPngImage(TFT_t * dev, char * file, int width, int height, int xpos, int
int _height = height;
if (height > 320) _height = 320;
pngle_t *pngle = pngle_new(_width, _height);
if (pngle == NULL) {
ESP_LOGE(__FUNCTION__, "pngle_new fail");
fclose(fp);
return;
}

pngle_set_init_callback(pngle, png_init);
pngle_set_draw_callback(pngle, png_draw);
Expand All @@ -1054,7 +1060,6 @@ void ShowPngImage(TFT_t * dev, char * file, int width, int height, int xpos, int
double display_gamma = 2.2;
pngle_set_display_gamma(pngle, display_gamma);


while (!feof(fp)) {
if (remain >= sizeof(buf)) {
ESP_LOGE(__FUNCTION__, "Buffer exceeded");
Expand Down
95 changes: 45 additions & 50 deletions main/pngle.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,9 @@
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "freertos/FreeRTOS.h"

#include "esp_log.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "miniz.h"
#else
#include "rom/miniz.h"
#endif
#include "pngle.h"

#define PNGLE_ERROR(s) (pngle->error = (s), pngle->state = PNGLE_STATE_ERROR, -1)
Expand All @@ -58,9 +53,9 @@ static inline uint8_t read_uint8(const uint8_t *p)
static inline uint32_t read_uint32(const uint8_t *p)
{
return (p[0] << 24)
| (p[1] << 16)
| (p[2] << 8)
| (p[3] << 0)
| (p[1] << 16)
| (p[2] << 8)
| (p[3] << 0)
;
}

Expand Down Expand Up @@ -412,7 +407,7 @@ static int pngle_on_data(pngle_t *pngle, const uint8_t *p, int len)
}

size_t cidx = pngle->scanline_ringbuf_cidx;
size_t bidx = (pngle->scanline_ringbuf_cidx + bytes_per_pixel) % pngle->scanline_ringbuf_size;
size_t bidx = (pngle->scanline_ringbuf_cidx + bytes_per_pixel) % pngle->scanline_ringbuf_size;
size_t aidx = (pngle->scanline_ringbuf_cidx + pngle->scanline_ringbuf_size - bytes_per_pixel) % pngle->scanline_ringbuf_size;
// debug_printf("[pngle] cidx = %zd, bidx = %zd, aidx = %zd\n", cidx, bidx, aidx);

Expand Down Expand Up @@ -457,59 +452,59 @@ static int pngle_handle_chunk(pngle_t *pngle, const uint8_t *buf, size_t len)
consume = 13;
if (len < consume) return 0;

debug_printf("[pngle] Parse IHDR\n");
debug_printf("[pngle] Parse IHDR\n");

pngle->hdr.width = read_uint32(buf + 0);
pngle->hdr.height = read_uint32(buf + 4);
pngle->hdr.depth = read_uint8 (buf + 8);
pngle->hdr.color_type = read_uint8 (buf + 9);
pngle->hdr.width = read_uint32(buf + 0);
pngle->hdr.height = read_uint32(buf + 4);
pngle->hdr.depth = read_uint8 (buf + 8);
pngle->hdr.color_type = read_uint8 (buf + 9);
pngle->hdr.compression = read_uint8 (buf + 10);
pngle->hdr.filter = read_uint8 (buf + 11);
pngle->hdr.interlace = read_uint8 (buf + 12);
pngle->hdr.filter = read_uint8 (buf + 11);
pngle->hdr.interlace = read_uint8 (buf + 12);


debug_printf("[pngle] width : %d\n", pngle->hdr.width);
debug_printf("[pngle] height : %d\n", pngle->hdr.height);
debug_printf("[pngle] depth : %d\n", pngle->hdr.depth);
debug_printf("[pngle] color_type : %d\n", pngle->hdr.color_type);
debug_printf("[pngle] compression: %d\n", pngle->hdr.compression);
debug_printf("[pngle] filter : %d\n", pngle->hdr.filter);
debug_printf("[pngle] interlace : %d\n", pngle->hdr.interlace);
debug_printf("[pngle] width : %d\n", pngle->hdr.width );
debug_printf("[pngle] height : %d\n", pngle->hdr.height );
debug_printf("[pngle] depth : %d\n", pngle->hdr.depth );
debug_printf("[pngle] color_type : %d\n", pngle->hdr.color_type );
debug_printf("[pngle] compression: %d\n", pngle->hdr.compression);
debug_printf("[pngle] filter : %d\n", pngle->hdr.filter );
debug_printf("[pngle] interlace : %d\n", pngle->hdr.interlace );

/*
Color Allowed Interpretation channels
Type Bit Depths
Color Allowed Interpretation channels
Type Bit Depths
0 1,2,4,8,16 Each pixel is a grayscale sample. 1 channels (Brightness)
0 1,2,4,8,16 Each pixel is a grayscale sample. 1 channels (Brightness)
2 8,16 Each pixel is an R,G,B triple. 3 channels (R, G, B)
2 8,16 Each pixel is an R,G,B triple. 3 channels (R, G, B)
3 1,2,4,8 Each pixel is a palette index; 1 channels (palette info)
a PLTE chunk must appear.
3 1,2,4,8 Each pixel is a palette index; 1 channels (palette info)
a PLTE chunk must appear.
4 8,16 Each pixel is a grayscale sample, 2 channels (Brightness, Alpha)
followed by an alpha sample.
4 8,16 Each pixel is a grayscale sample, 2 channels (Brightness, Alpha)
followed by an alpha sample.
6 8,16 Each pixel is an R,G,B triple, 4 channels (R, G, B, Alpha)
followed by an alpha sample.
6 8,16 Each pixel is an R,G,B triple, 4 channels (R, G, B, Alpha)
followed by an alpha sample.
*/
// 111
// ^-- indexed color (palette)
// ^--- Color
// ^---- Alpha channel
// 111
// ^-- indexed color (palette)
// ^--- Color
// ^---- Alpha channel

switch (pngle->hdr.color_type) {
case 0: pngle->channels = 1; if (pngle->hdr.depth != 1 && pngle->hdr.depth != 2 && pngle->hdr.depth != 4 && pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // grayscale
case 2: pngle->channels = 3; if (pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor
case 3: pngle->channels = 1; if (pngle->hdr.depth != 1 && pngle->hdr.depth != 2 && pngle->hdr.depth != 4 && pngle->hdr.depth != 8) return PNGLE_ERROR("Invalid bit depth"); break; // indexed color
case 4: pngle->channels = 2; if (pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // grayscale + alpha
case 6: pngle->channels = 4; if (pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor + alpha
case 2: pngle->channels = 3; if ( pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor
case 3: pngle->channels = 1; if (pngle->hdr.depth != 1 && pngle->hdr.depth != 2 && pngle->hdr.depth != 4 && pngle->hdr.depth != 8 ) return PNGLE_ERROR("Invalid bit depth"); break; // indexed color
case 4: pngle->channels = 2; if ( pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // grayscale + alpha
case 6: pngle->channels = 4; if ( pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor + alpha
default:
return PNGLE_ERROR("Incorrect IHDR info");
}

if (pngle->hdr.compression != 0) return PNGLE_ERROR("Unsupported compression type in IHDR");
if (pngle->hdr.filter != 0) return PNGLE_ERROR("Unsupported filter type in IHDR");
if (pngle->hdr.filter != 0) return PNGLE_ERROR("Unsupported filter type in IHDR");

// interlace
if (set_interlace_pass(pngle, pngle->hdr.interlace ? 1 : 0) < 0) return -1;
Expand All @@ -523,29 +518,29 @@ static int pngle_handle_chunk(pngle_t *pngle, const uint8_t *buf, size_t len)
// parse & decode IDAT chunk
if (len < 1) return 0;

debug_printf("[pngle] Reading IDAT (len %zd / chunk remain %u)\n", len, pngle->chunk_remain);
debug_printf("[pngle] Reading IDAT (len %zd / chunk remain %u)\n", len, pngle->chunk_remain);

size_t in_bytes = len;
size_t out_bytes = pngle->avail_out;

//debug_printf("[pngle] in_bytes %zd, out_bytes %zd, next_out %p\n", in_bytes, out_bytes, pngle->next_out);
//debug_printf("[pngle] in_bytes %zd, out_bytes %zd, next_out %p\n", in_bytes, out_bytes, pngle->next_out);

// XXX: tinfl_decompress always requires (next_out - lz_buf + avail_out) == TINFL_LZ_DICT_SIZE
tinfl_status status = tinfl_decompress(&pngle->inflator, (const mz_uint8 *)buf, &in_bytes, pngle->lz_buf, (mz_uint8 *)pngle->next_out, &out_bytes, TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_PARSE_ZLIB_HEADER);

//debug_printf("[pngle] tinfl_decompress\n");
//debug_printf("[pngle] => in_bytes %zd, out_bytes %zd, next_out %p, status %d\n", in_bytes, out_bytes, pngle->next_out, status);
//debug_printf("[pngle] tinfl_decompress\n");
//debug_printf("[pngle] => in_bytes %zd, out_bytes %zd, next_out %p, status %d\n", in_bytes, out_bytes, pngle->next_out, status);

if (status < TINFL_STATUS_DONE) {
// Decompression failed.
debug_printf("[pngle] tinfl_decompress() failed with status %d!\n", status);
return PNGLE_ERROR("Failed to decompress the IDAT stream");
}

pngle->next_out += out_bytes;
pngle->avail_out -= out_bytes;
pngle->next_out += out_bytes;
pngle->avail_out -= out_bytes;

// debug_printf("[pngle] => avail_out %zd, next_out %p\n", pngle->avail_out, pngle->next_out);
// debug_printf("[pngle] => avail_out %zd, next_out %p\n", pngle->avail_out, pngle->next_out);

if (status == TINFL_STATUS_DONE || pngle->avail_out == 0) {
// Output buffer is full, or decompression is done, so write buffer to output file.
Expand Down Expand Up @@ -587,7 +582,7 @@ static int pngle_handle_chunk(pngle_t *pngle, const uint8_t *buf, size_t len)

case PNGLE_CHUNK_tRNS:
switch (pngle->hdr.color_type) {
case 3: consume = 1; break;
case 3: consume = 1; break;
case 0: consume = 2 * 1; break;
case 2: consume = 2 * 3; break;
default:
Expand Down
106 changes: 50 additions & 56 deletions main/pngle.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,7 @@

#include <stdint.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "miniz.h"
#else
#include "rom/miniz.h"
#endif

#ifdef __cplusplus
extern "C" {
Expand All @@ -53,36 +47,36 @@ extern "C" {

#if 0
typedef struct __attribute__((__packed__)) {
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t red;
uint8_t green;
uint8_t blue;
} pixel_png;
#endif

//rgb565 format
typedef uint16_t pixel_png;

typedef enum {
PNGLE_STATE_ERROR = -2,
PNGLE_STATE_EOF = -1,
PNGLE_STATE_INITIAL = 0,
PNGLE_STATE_ERROR = -2,
PNGLE_STATE_EOF = -1,
PNGLE_STATE_INITIAL = 0,

PNGLE_STATE_FIND_CHUNK_HEADER,
PNGLE_STATE_HANDLE_CHUNK,
PNGLE_STATE_CRC,
PNGLE_STATE_FIND_CHUNK_HEADER,
PNGLE_STATE_HANDLE_CHUNK,
PNGLE_STATE_CRC,
} pngle_state_t;


typedef enum {
// Supported chunks
// Filter chunk names by following command to (re)generate hex constants;
// % perl -ne 'chomp; s/.*\s*\/\/\s*//; print "\tPNGLE_CHUNK_$_ = 0x" . unpack("H*") . "UL, // $_\n";'
PNGLE_CHUNK_IHDR = 0x49484452UL, // IHDR
PNGLE_CHUNK_PLTE = 0x504c5445UL, // PLTE
PNGLE_CHUNK_IDAT = 0x49444154UL, // IDAT
PNGLE_CHUNK_IEND = 0x49454e44UL, // IEND
PNGLE_CHUNK_tRNS = 0x74524e53UL, // tRNS
PNGLE_CHUNK_gAMA = 0x67414d41UL, // gAMA
PNGLE_CHUNK_IHDR = 0x49484452UL, // IHDR
PNGLE_CHUNK_PLTE = 0x504c5445UL, // PLTE
PNGLE_CHUNK_IDAT = 0x49444154UL, // IDAT
PNGLE_CHUNK_IEND = 0x49454e44UL, // IEND
PNGLE_CHUNK_tRNS = 0x74524e53UL, // tRNS
PNGLE_CHUNK_gAMA = 0x67414d41UL, // gAMA
} pngle_chunk_t;

typedef struct _pngle_ihdr_t {
Expand All @@ -104,54 +98,54 @@ typedef void (*pngle_draw_callback_t)(pngle_t *pngle, uint32_t x, uint32_t y, ui
typedef void (*pngle_done_callback_t)(pngle_t *pngle);

struct pngle {
pngle_ihdr_t hdr;
pngle_ihdr_t hdr;

uint_fast8_t channels; // 0 indicates IHDR hasn't been processed yet
uint_fast8_t channels; // 0 indicates IHDR hasn't been processed yet

// PLTE chunk
size_t n_palettes;
uint8_t *palette;
// PLTE chunk
size_t n_palettes;
uint8_t *palette;

// tRNS chunk
size_t n_trans_palettes;
uint8_t *trans_palette;
// tRNS chunk
size_t n_trans_palettes;
uint8_t *trans_palette;

// parser state (reset on every chunk header)
pngle_state_t state;
uint32_t chunk_type;
uint32_t chunk_remain;
mz_ulong crc32;
// parser state (reset on every chunk header)
pngle_state_t state;
uint32_t chunk_type;
uint32_t chunk_remain;
mz_ulong crc32;

// decompression state (reset on IHDR)
tinfl_decompressor inflator; // 11000 bytes
uint8_t lz_buf[TINFL_LZ_DICT_SIZE]; // 32768 bytes
uint8_t *next_out; // NULL indicates IDAT hasn't been processed yet
size_t avail_out;
// decompression state (reset on IHDR)
tinfl_decompressor inflator; // 11000 bytes
uint8_t lz_buf[TINFL_LZ_DICT_SIZE]; // 32768 bytes
uint8_t *next_out; // NULL indicates IDAT hasn't been processed yet
size_t avail_out;

// scanline decoder (reset on every set_interlace_pass() call)
uint8_t *scanline_ringbuf;
size_t scanline_ringbuf_size;
size_t scanline_ringbuf_cidx;
int_fast8_t scanline_remain_bytes_to_render;
int_fast8_t filter_type;
uint32_t drawing_x;
uint32_t drawing_y;
// scanline decoder (reset on every set_interlace_pass() call)
uint8_t *scanline_ringbuf;
size_t scanline_ringbuf_size;
size_t scanline_ringbuf_cidx;
int_fast8_t scanline_remain_bytes_to_render;
int_fast8_t filter_type;
uint32_t drawing_x;
uint32_t drawing_y;

// interlace
uint_fast8_t interlace_pass;
// interlace
uint_fast8_t interlace_pass;

const char *error;
const char *error;

#ifndef PNGLE_NO_GAMMA_CORRECTION
uint8_t *gamma_table;
double display_gamma;
uint8_t *gamma_table;
double display_gamma;
#endif

pngle_init_callback_t init_callback;
pngle_draw_callback_t draw_callback;
pngle_done_callback_t done_callback;
pngle_init_callback_t init_callback;
pngle_draw_callback_t draw_callback;
pngle_done_callback_t done_callback;

void *user_data;
void *user_data;
uint16_t screenWidth;
uint16_t screenHeight;
uint16_t imageWidth;
Expand Down

0 comments on commit 1c4b847

Please sign in to comment.