diff --git a/src/guacenc/image-stream.c b/src/guacenc/image-stream.c index fd442e1d..02872cd1 100644 --- a/src/guacenc/image-stream.c +++ b/src/guacenc/image-stream.c @@ -133,8 +133,11 @@ int guacenc_image_stream_end(guacenc_image_stream* stream, return 1; /* Draw surface to buffer */ - cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y); - cairo_fill(buffer->cairo); + if (buffer->cairo != NULL) { + cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y); + cairo_fill(buffer->cairo); + } + cairo_surface_destroy(surface); return 0; diff --git a/src/guacenc/png.c b/src/guacenc/png.c index 68b4d741..abf1e58e 100644 --- a/src/guacenc/png.c +++ b/src/guacenc/png.c @@ -21,14 +21,92 @@ */ #include "config.h" +#include "log.h" #include "png.h" #include #include +#include + +/** + * The current state of the PNG decoder. + */ +typedef struct guacenc_png_read_state { + + /** + * The buffer of unread image data. This pointer will be updated to point + * to the next unread byte when data is read. + */ + unsigned char* data; + + /** + * The number of bytes remaining to be read within the buffer. + */ + unsigned int length; + +} guacenc_png_read_state; + +/** + * Attempts to fill the given buffer with read image data. The behavior of + * this function is dictated by cairo_read_t. + * + * @param closure + * The current state of the PNG decoding process (an instance of + * guacenc_png_read_state). + * + * @param data + * The data buffer to fill. + * + * @param length + * The number of bytes to fill within the data buffer. + * + * @return + * CAIRO_STATUS_SUCCESS if all data was read successfully (the entire + * buffer was filled), CAIRO_STATUS_READ_ERROR otherwise. + */ +static cairo_status_t guacenc_png_read(void* closure, unsigned char* data, + unsigned int length) { + + guacenc_png_read_state* state = (guacenc_png_read_state*) closure; + + /* If more data is requested than is available in buffer, fail */ + if (length > state->length) + return CAIRO_STATUS_READ_ERROR; + + /* Read chunk into buffer */ + memcpy(data, state->data, length); + + /* Advance to next chunk */ + state->length -= length; + state->data += length; + + /* Read was successful */ + return CAIRO_STATUS_SUCCESS; + +} + +cairo_surface_t* guacenc_png_decoder(unsigned char* data, int length) { + + guacenc_png_read_state state = { + .data = data, + .length = length + }; + + /* Read PNG from data */ + cairo_surface_t* surface = + cairo_image_surface_create_from_png_stream(guacenc_png_read, &state); + + /* If surface returned with an error, just return NULL */ + if (surface != NULL && + cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { + guacenc_log(GUAC_LOG_WARNING, "Invalid PNG data"); + cairo_surface_destroy(surface); + return NULL; + } + + /* PNG was read successfully */ + return surface; -cairo_surface_t* guacenc_png_decoder(unsigned char* data, int length) { - /* STUB */ - return NULL; }