Skip to content

Commit

Permalink
Better PNG load error reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
kovidgoyal committed Nov 23, 2023
1 parent 35b2dcb commit 79f3692
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 14 deletions.
21 changes: 16 additions & 5 deletions kitty/graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ inflate_zlib(LoadData *load_data, uint8_t *buf, size_t bufsz) {
}

static void
png_error_handler(const char *code, const char *msg) {
png_error_handler(png_read_data *d UNUSED, const char *code, const char *msg) {
set_command_failed_response(code, "%s", msg);
}

Expand Down Expand Up @@ -333,6 +333,17 @@ add_trim_predicate(Image *img) {
return !img->root_frame_data_loaded || (!img->client_id && !img->refs);
}

static void
print_png_read_error(png_read_data *d, const char *code, const char* msg) {
if (d->error.used >= d->error.capacity) {
size_t cap = MAX(2 * d->error.capacity, 1024 + d->error.used);
d->error.buf = realloc(d->error.buf, cap);
if (!d->error.buf) return;
d->error.capacity = cap;
}
d->error.used += snprintf(d->error.buf + d->error.used, d->error.capacity - d->error.used, "%s: %s ", code, msg);
}

bool
png_from_file_pointer(FILE *fp, const char *path_for_error_messages, uint8_t** data, unsigned int* width, unsigned int* height, size_t* sz) {
size_t capacity = 16*1024, pos = 0;
Expand All @@ -356,16 +367,16 @@ png_from_file_pointer(FILE *fp, const char *path_for_error_messages, uint8_t** d
return false;
}
}
png_read_data d = {0};
png_read_data d = {.err_handler=print_png_read_error};
inflate_png_inner(&d, buf, pos);
free(buf);
if (!d.ok) {
free(d.decompressed); free(d.row_pointers);
log_error("Failed to decode PNG image at: %s", path_for_error_messages);
log_error("Failed to decode PNG image at: %s with error: %s", path_for_error_messages, d.error.used > 0 ? d.error.buf : "");
free(d.decompressed); free(d.row_pointers); free(d.error.buf);
return false;
}
*data = d.decompressed;
free(d.row_pointers);
free(d.row_pointers); free(d.error.buf);
*sz = d.sz;
*height = d.height; *width = d.width;
return true;
Expand Down
13 changes: 7 additions & 6 deletions kitty/png-reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Distributed under terms of the GPL3 license.
*/

#include "data-types.h"
#include "png-reader.h"
#include "cleanup.h"
#include "state.h"
Expand All @@ -26,15 +27,15 @@ read_png_from_buffer(png_structp png, png_bytep out, png_size_t length) {

struct custom_error_handler {
jmp_buf jb;
png_error_handler_func err_handler;
png_read_data *d;
};

static void
read_png_error_handler(png_structp png_ptr, png_const_charp msg) {
struct custom_error_handler *eh;
eh = png_get_error_ptr(png_ptr);
if (eh == NULL) fatal("read_png_error_handler: could not retrieve error handler");
if(eh->err_handler) eh->err_handler("EBADPNG", msg);
if(eh->d->err_handler) eh->d->err_handler(eh->d, "EBADPNG", msg);
longjmp(eh->jb, 1);
}

Expand All @@ -43,14 +44,14 @@ read_png_warn_handler(png_structp UNUSED png_ptr, png_const_charp msg) {
if (global_state.debug_rendering) log_error("libpng WARNING: %s", msg);
}

#define ABRT(code, msg) { if(d->err_handler) d->err_handler(#code, msg); goto err; }
#define ABRT(code, msg) { if(d->err_handler) d->err_handler(d, #code, msg); goto err; }

void
inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz) {
struct fake_file f = {.buf = buf, .sz = bufsz};
png_structp png = NULL;
png_infop info = NULL;
struct custom_error_handler eh = {.err_handler = d->err_handler};
struct custom_error_handler eh = {.d = d};
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, &eh, read_png_error_handler, read_png_warn_handler);
if (!png) ABRT(ENOMEM, "Failed to create PNG read structure");
info = png_create_info_struct(png);
Expand Down Expand Up @@ -131,8 +132,8 @@ inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz) {
}

static void
png_error_handler(const char *code, const char *msg) {
PyErr_Format(PyExc_ValueError, "[%s] %s", code, msg);
png_error_handler(png_read_data *d UNUSED, const char *code, const char *msg) {
if (!PyErr_Occurred()) PyErr_Format(PyExc_ValueError, "[%s] %s", code, msg);
}

static PyObject*
Expand Down
15 changes: 12 additions & 3 deletions kitty/png-reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@

#pragma once

#include "data-types.h"
#include <stdint.h>
#include <stdbool.h>
#include <png.h>
typedef void(*png_error_handler_func)(const char*, const char*);
typedef struct {

typedef struct png_read_data png_read_data;

typedef void(*png_error_handler_func)(png_read_data *d, const char*, const char*);

typedef struct png_read_data {
uint8_t *decompressed;
bool ok;
png_bytep *row_pointers;
int width, height;
size_t sz;
png_error_handler_func err_handler;
struct {
char *buf;
size_t used, capacity;
} error;
} png_read_data;

void inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz);

0 comments on commit 79f3692

Please sign in to comment.