From: Michael Orlitzky Date: Sat, 5 Aug 2023 01:27:31 +0000 (-0400) Subject: io-svg.c: miscellaneous documentation and error-handling improvements. X-Git-Tag: 0.0.1~34 X-Git-Url: https://gitweb.michael.orlitzky.com/?a=commitdiff_plain;h=ce61daf00d9a18bcbbbff7709d9c59c3c0d2dbbb;p=libsvgtiny-pixbuf.git io-svg.c: miscellaneous documentation and error-handling improvements. --- diff --git a/io-svg.c b/io-svg.c index 521ed58..750ea25 100644 --- a/io-svg.c +++ b/io-svg.c @@ -1,9 +1,9 @@ #include /* fopen, fprintf, fread, printf */ -#include /* malloc */ +#include /* memcpy */ #include #include -#include +#include /* includes glib.h */ #include /* @@ -65,64 +65,67 @@ static void render_path(cairo_t* cr, shape_t* path) { break; case svgtiny_PATH_LINE: cairo_line_to(cr, - path->path[j + 1], - path->path[j + 2]); + path->path[j + 1], + path->path[j + 2]); j += 3; break; case svgtiny_PATH_BEZIER: cairo_curve_to(cr, - path->path[j + 1], - path->path[j + 2], - path->path[j + 3], - path->path[j + 4], - path->path[j + 5], - path->path[j + 6]); + path->path[j + 1], + path->path[j + 2], + path->path[j + 3], + path->path[j + 4], + path->path[j + 5], + path->path[j + 6]); j += 7; - break; - default: - fprintf(stderr, "error: unmatched case in render_path\n"); - j += 1; } } if (path->fill != svgtiny_TRANSPARENT) { cairo_set_source_rgba(cr, - svgtiny_RED(path->fill) / 255.0, - svgtiny_GREEN(path->fill) / 255.0, - svgtiny_BLUE(path->fill) / 255.0, - 1); + svgtiny_RED(path->fill) / 255.0, + svgtiny_GREEN(path->fill) / 255.0, + svgtiny_BLUE(path->fill) / 255.0, + 1); cairo_fill_preserve(cr); } if (path->stroke != svgtiny_TRANSPARENT) { cairo_set_source_rgba(cr, - svgtiny_RED(path->stroke) / 255.0, - svgtiny_GREEN(path->stroke) / 255.0, - svgtiny_BLUE(path->stroke) / 255.0, - 1); + svgtiny_RED(path->stroke) / 255.0, + svgtiny_GREEN(path->stroke) / 255.0, + svgtiny_BLUE(path->stroke) / 255.0, + 1); cairo_set_line_width(cr, path->stroke_width); cairo_stroke_preserve(cr); } } /** - * @brief Parse an SVG file into a diagram_t structure. + * @brief Parse a buffer of SVG data into a diagram_t structure. * - * @param fp - * A pointer to an open file stream. + * @param buffer + * The buffer containing the SVG document. + * + * @param bytecount + * The number of bytes in @c buffer. * * @return If successful, a pointer to a @c diagram_t structure is * returned; if not, @c NULL is returned. You are expected to @c * svgtiny_free the result if it is valid. */ static diagram_t* svgtiny_diagram_from_buffer(char* buffer, - size_t bytecount, - int width, - int height) { + size_t bytecount, + int width, + int height, + GError** error) { diagram_t* diagram; svgtiny_code code; diagram = svgtiny_create(); if (!diagram) { - fprintf(stderr, "svgtiny_create() failed\n"); + g_set_error_literal(error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + "svgtiny_create() failed"); return NULL; } @@ -130,27 +133,34 @@ static diagram_t* svgtiny_diagram_from_buffer(char* buffer, free(buffer); if (code != svgtiny_OK) { - fprintf(stderr, "svgtiny_parse failed with "); switch (code) { case svgtiny_OUT_OF_MEMORY: - fprintf(stderr, "svgtiny_OUT_OF_MEMORY"); + g_set_error_literal(error, + G_FILE_ERROR, + G_FILE_ERROR_NOMEM, + "out of memory in svgtiny_parse()"); break; case svgtiny_LIBDOM_ERROR: - fprintf(stderr, "svgtiny_LIBDOM_ERROR"); + g_set_error_literal(error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + "libdom error in svgtiny_parse()"); break; case svgtiny_NOT_SVG: - fprintf(stderr, "svgtiny_NOT_SVG"); + g_set_error_literal(error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + "encountered svgtiny_NOT_SVG in svgtiny_parse()"); break; case svgtiny_SVG_ERROR: - fprintf(stderr, "svgtiny_SVG_ERROR: line %i: %s", - diagram->error_line, - diagram->error_message); - break; - default: - fprintf(stderr, "unknown svgtiny_code %i", code); + g_set_error(error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + "SVG error in svgtiny_parse() on line %i: %s", + diagram->error_line, + diagram->error_message); break; } - fprintf(stderr, "\n"); return NULL; } @@ -174,14 +184,14 @@ static cairo_t* cairo_context_from_diagram(diagram_t* diagram) { unsigned int i; surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - diagram->width, - diagram->height); + diagram->width, + diagram->height); crs = cairo_surface_status(surface); if (crs != CAIRO_STATUS_SUCCESS) { fprintf(stderr, - "cairo_image_surface_create failed: %s\n", - cairo_status_to_string(crs)); + "cairo_image_surface_create failed: %s\n", + cairo_status_to_string(crs)); cairo_surface_destroy(surface); return NULL; } @@ -195,8 +205,8 @@ static cairo_t* cairo_context_from_diagram(diagram_t* diagram) { if (crs != CAIRO_STATUS_SUCCESS) { fprintf(stderr, - "cairo_create failed: %s\n", - cairo_status_to_string(crs)); + "cairo_create failed: %s\n", + cairo_status_to_string(crs)); cairo_destroy(cr); return NULL; } @@ -215,17 +225,17 @@ static cairo_t* cairo_context_from_diagram(diagram_t* diagram) { /* If this shape is text... */ if (diagram->shape[i].text) { /* Figure out what color to use from the R/G/B components of the - shape's stroke. */ + shape's stroke. */ cairo_set_source_rgba(cr, - svgtiny_RED(diagram->shape[i].stroke) / 255.0, - svgtiny_GREEN(diagram->shape[i].stroke) / 255.0, - svgtiny_BLUE(diagram->shape[i].stroke) / 255.0, - 1); + svgtiny_RED(diagram->shape[i].stroke) / 255.0, + svgtiny_GREEN(diagram->shape[i].stroke) / 255.0, + svgtiny_BLUE(diagram->shape[i].stroke) / 255.0, + 1); /* Then move to the actual position of the text within the - shape... */ + shape... */ cairo_move_to(cr, - diagram->shape[i].text_x, - diagram->shape[i].text_y); + diagram->shape[i].text_x, + diagram->shape[i].text_y); /* and draw it. */ cairo_show_text(cr, diagram->shape[i].text); @@ -246,22 +256,36 @@ static cairo_t* cairo_context_from_diagram(diagram_t* diagram) { return cr; } +/** + * @brief Create a GdkPixbuf from a buffer of SVG data. + * + * @param buffer + * The buffer containing the SVG document. + * + * @param bytecount + * The number of bytes in @c buffer. + * + * @param error + * The address of a @c GError pointer that we use to return errors. + * + * @return If successful, a valid pointer to a @c GdkPixbuf is + * returned; if not, @c NULL is returned and @c error is populated. + */ static GdkPixbuf* gdk_pixbuf_from_svg_buffer(char* buffer, size_t bytecount, GError** error) { diagram_t* diagram; cairo_t* cr = 0; GdkPixbuf* pb; + GError* sub_error = NULL; diagram = svgtiny_diagram_from_buffer(buffer, bytecount, VIEWPORT_WIDTH, - VIEWPORT_HEIGHT); + VIEWPORT_HEIGHT, + &sub_error); if (!diagram) { - g_set_error_literal(error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - "Could not parse SVG diagram from file"); + g_propagate_error(error, sub_error); return NULL; } @@ -271,7 +295,7 @@ static GdkPixbuf* gdk_pixbuf_from_svg_buffer(char* buffer, g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - "Could not create Cairo surface from SVG diagram"); + "could not create Cairo surface from SVG diagram"); return NULL; } @@ -297,12 +321,28 @@ static GdkPixbuf* gdk_pixbuf_from_svg_buffer(char* buffer, g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, - "Failed to obtain a GdkPixbuf from Cairo surface"); + "failed to obtain a GdkPixbuf from Cairo surface"); } return pb; } + +/** + * @brief Create a GdkPixbuf from an SVG filestream. + * + * This is essentially a wrapper around @gdk_pixbuf_from_svg_buffer + * that reads a @c FILE pointer into a buffer. + * + * @param fp + * A pointer to a @c FILE containing the SVG document. + * + * @param error + * The address of a @c GError pointer that we use to return errors. + * + * @return If successful, a valid pointer to a @c GdkPixbuf is + * returned; if not, @c NULL is returned and @c error is populated. + */ static GdkPixbuf* gdk_pixbuf_from_svg_file_stream(FILE *fp, GError** error) { size_t bytecount, bytesread; char* buffer; @@ -312,19 +352,19 @@ static GdkPixbuf* gdk_pixbuf_from_svg_file_stream(FILE *fp, GError** error) { bytecount = ftell(fp); rewind(fp); - buffer = malloc(bytecount); - if (!buffer) { - fprintf(stderr, "Unable to allocate %zd bytes\n", bytecount); - return NULL; - } + /* YOLO, no error checking */ + buffer = g_malloc(bytecount); bytesread = fread(buffer, 1, bytecount, fp); if (bytesread != bytecount) { - fprintf(stderr, "Read only %zd of %zd bytes from stream\n", - bytesread, - bytecount); + g_set_error(error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + "read only %zd of %zd bytes from stream", + bytesread, + bytecount); + return NULL; } - fclose(fp); return gdk_pixbuf_from_svg_buffer(buffer, bytecount, error); } @@ -336,22 +376,16 @@ static gpointer gdk_pixbuf_begin_load(GdkPixbufModuleSizeFunc size_func, gpointer user_data, GError **error) { - SvgTinyContext* context = g_new0(SvgTinyContext, 1); + SvgTinyContext* context = g_new(SvgTinyContext, 1); context->size_func = size_func; context->prepared_func = prep_func; context->updated_func = updated_func; context->user_data = user_data; - context->svg_data = malloc(SVG_BUFFER_INCREMENT); - if (context->svg_data) { - context->svg_data_size = 0; - context->svg_data_max = SVG_BUFFER_INCREMENT; - } - else { - fprintf(stderr, "Unable to allocate %zd bytes\n", SVG_BUFFER_INCREMENT); - return NULL; - } + /* YOLO, no error checking */ + context->svg_data = g_malloc(SVG_BUFFER_INCREMENT); + context->svg_data_size = 0; return context; } @@ -360,26 +394,24 @@ static gboolean gdk_pixbuf_load_increment(gpointer data, const guchar* buf, guint size, GError** error) { + size_t increment = 0; SvgTinyContext* context = (SvgTinyContext*)data; if (context->svg_data_size + size > context->svg_data_max) { - size_t increment = 0; if (size > SVG_BUFFER_INCREMENT) { increment = size; } else { increment = SVG_BUFFER_INCREMENT; } - context->svg_data = realloc(context->svg_data, - context->svg_data_max + increment); - if (context->svg_data) { - context->svg_data_max += increment; - } - else { - fprintf(stderr, "Unable to (re)allocate %zd bytes\n", increment); - return FALSE; - } + + /* YOLO, no error checking */ + context->svg_data = g_realloc(context->svg_data, + context->svg_data_max + increment); + + context->svg_data_max += increment; } + memcpy(context->svg_data + context->svg_data_size, buf, size); context->svg_data_size += size; @@ -406,7 +438,6 @@ static void emit_prepared(SvgTinyContext* context, GdkPixbuf* pixbuf) { /* static void emit_size(SvgTinyContext* context, GdkPixbuf* pixbuf) { - int w = gdk_pixbuf_get_width(pixbuf); int h = gdk_pixbuf_get_height(pixbuf); if (context->size_func != NULL) { @@ -415,25 +446,28 @@ static void emit_size(SvgTinyContext* context, GdkPixbuf* pixbuf) { } */ + static gboolean gdk_pixbuf_stop_load(gpointer data, GError **error) { SvgTinyContext* context = (SvgTinyContext*)data; GdkPixbuf* pixbuf = NULL; gboolean result = TRUE; + GError* sub_error = NULL; pixbuf = gdk_pixbuf_from_svg_buffer(context->svg_data, context->svg_data_size, - error); + &sub_error); if (pixbuf != NULL) { - /* emit_size(context, pixbuf); */ + /*emit_size(context, pixbuf);*/ emit_prepared(context, pixbuf); emit_updated(context, pixbuf); g_object_unref(pixbuf); } else { + g_propagate_error(error, sub_error); result = FALSE; } - g_free (context); + g_free(context); return result; } @@ -510,9 +544,9 @@ int main(int argc, char** argv) { pb = gdk_pixbuf_from_svg_file_stream(fp, &err); if (!pb) { fprintf(stderr, - "Error %d in gdk_pixbuf_from_svg_file_stream: %s\n", - err->code, - err->message); + "Error %d in gdk_pixbuf_from_svg_file_stream: %s\n", + err->code, + err->message); g_error_free(err); return 1; }