diff options
author | Michael Drake <tlsa@netsurf-browser.org> | 2022-02-25 16:57:49 +0000 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2022-02-26 10:29:29 +0000 |
commit | f19985bde06da13b2a1396756b2c82300296f8c8 (patch) | |
tree | 9141b23a40c6c9f7fb662eea38cc18f1a72ea80d | |
parent | aad22e646509b7393f89b77f59894fba52031b7c (diff) | |
download | libnsgif-f19985bde06da13b2a1396756b2c82300296f8c8.tar.gz libnsgif-f19985bde06da13b2a1396756b2c82300296f8c8.tar.bz2 |
API: Clean up error codes and add nsgif_strerror function.
-rw-r--r-- | include/nsgif.h | 104 | ||||
-rw-r--r-- | src/gif.c | 212 | ||||
-rw-r--r-- | test/decode_gif.c | 49 |
3 files changed, 207 insertions, 158 deletions
diff --git a/include/nsgif.h b/include/nsgif.h index 1472842..f03d121 100644 --- a/include/nsgif.h +++ b/include/nsgif.h @@ -39,20 +39,61 @@ typedef struct nsgif_info { uint16_t delay_min; } nsgif_info_t; -/* Error return values */ +/** + * NSGIF return codes. + */ typedef enum { - NSGIF_WORKING = 1, - NSGIF_OK = 0, - NSGIF_INSUFFICIENT_DATA = -1, - NSGIF_INSUFFICIENT_FRAME_DATA = NSGIF_INSUFFICIENT_DATA, - NSGIF_FRAME_DATA_ERROR = -2, - NSGIF_DATA_ERROR = -4, - NSGIF_INSUFFICIENT_MEMORY = -5, - NSGIF_FRAME_NO_DISPLAY = -6, - NSGIF_END_OF_FRAME = -7, - NSGIF_FRAME_INVALID = -8, - NSGIF_ANIMATION_COMPLETE = -9, -} nsgif_result; + /** + * Success. + */ + NSGIF_OK, + + /** + * Out of memory error. + */ + NSGIF_ERR_OOM, + + /** + * GIF source data is invalid, and no frames are recoverable. + */ + NSGIF_ERR_DATA, + + /** + * Frame number is not valid. + */ + NSGIF_ERR_BAD_FRAME, + + /** + * GIF source data contained an error in a frame. + */ + NSGIF_ERR_DATA_FRAME, + + /** + * Too many frames. + */ + NSGIF_ERR_FRAME_COUNT, + + /** + * GIF source data ended without one complete frame available. + */ + NSGIF_ERR_END_OF_DATA, + + /** + * GIF source data ended with incomplete frame. + */ + NSGIF_ERR_END_OF_FRAME, + + /** + * The current frame cannot be displayed. + */ + NSGIF_ERR_FRAME_DISPLAY, + + /** + * Indicates an animation is complete, and \ref nsgif_reset must be + * called to restart the animation from the beginning. + */ + NSGIF_ERR_ANIMATION_END, +} nsgif_error; /** * GIF rectangle structure. @@ -136,13 +177,22 @@ typedef struct nsgif_bitmap_cb_vt { } nsgif_bitmap_cb_vt; /** + * Convert an error code to a string. + * + * \param[in] err The error code to convert. + * \return String representation of given error code. + */ +const char *nsgif_strerror(nsgif_error err); + +/** * Create the NSGIF object. * * \param[in] bitmap_vt Bitmap operation functions v-table. * \param[out] gif_out Return NSGIF object on success. + * * \return NSGIF_OK on success, or appropriate error otherwise. */ -nsgif_result nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif **gif_out); +nsgif_error nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif **gif_out); /** * Scan the source image data. @@ -166,15 +216,9 @@ nsgif_result nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif **gif_out); * \param[in] size Number of bytes in data. * \param[in] data Raw source GIF data. * - * \return Error return value. - * - NSGIF_FRAME_DATA_ERROR for GIF frame data error - * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data - * - NSGIF_INSUFFICIENT_MEMORY for memory error - * - NSGIF_DATA_ERROR for GIF error - * - NSGIF_OK for successful decoding - * - NSGIF_WORKING for successful decoding if more frames are expected + * \return NSGIF_OK on success, or appropriate error otherwise. */ -nsgif_result nsgif_data_scan( +nsgif_error nsgif_data_scan( nsgif *gif, size_t size, const uint8_t *data); @@ -186,8 +230,10 @@ nsgif_result nsgif_data_scan( * \param[out] area The area in pixels that must be redrawn. * \param[out] delay_cs Time to wait after frame_new before next frame in cs. * \param[out] frame_new The frame to decode. + * + * \return NSGIF_OK on success, or appropriate error otherwise. */ -nsgif_result nsgif_frame_prepare( +nsgif_error nsgif_frame_prepare( nsgif *gif, nsgif_rect *area, uint32_t *delay_cs, @@ -200,14 +246,10 @@ nsgif_result nsgif_frame_prepare( * \param[in] frame The frame number to decode. * \param[out] bitmap On success, returns pointer to the client-allocated, * nsgif-owned client bitmap structure. - * \return Error return value. - * - NSGIF_FRAME_DATA_ERROR for GIF frame data error - * - NSGIF_DATA_ERROR for GIF error (invalid frame header) - * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data - * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process - * - NSGIF_OK for successful decoding + * + * \return NSGIF_OK on success, or appropriate error otherwise. */ -nsgif_result nsgif_frame_decode( +nsgif_error nsgif_frame_decode( nsgif *gif, uint32_t frame, nsgif_bitmap_t **bitmap); @@ -224,7 +266,7 @@ nsgif_result nsgif_frame_decode( * * \return NSGIF_OK on success, or appropriate error otherwise. */ -nsgif_result nsgif_reset( +nsgif_error nsgif_reset( nsgif *gif); /** @@ -104,6 +104,14 @@ struct nsgif { }; /** + * Helper macro to get number of elements in an array. + * + * \param[in] _a Array to count elements of. + * \return NUlber of elements in array. + */ +#define NSGIF_ARRAY_LEN(_a) ((sizeof(_a)) / (sizeof(*_a))) + +/** * * \file * \brief GIF image decoder @@ -146,16 +154,16 @@ enum nsgif_disposal { * \param[in] l_res LZW response code. * \return GIF result code. */ -static nsgif_result nsgif__error_from_lzw(lzw_result l_res) +static nsgif_error nsgif__error_from_lzw(lzw_result l_res) { - static const nsgif_result g_res[] = { + static const nsgif_error g_res[] = { [LZW_OK] = NSGIF_OK, - [LZW_OK_EOD] = NSGIF_END_OF_FRAME, - [LZW_NO_MEM] = NSGIF_INSUFFICIENT_MEMORY, - [LZW_NO_DATA] = NSGIF_INSUFFICIENT_DATA, - [LZW_EOI_CODE] = NSGIF_FRAME_DATA_ERROR, - [LZW_BAD_ICODE] = NSGIF_FRAME_DATA_ERROR, - [LZW_BAD_CODE] = NSGIF_FRAME_DATA_ERROR, + [LZW_NO_MEM] = NSGIF_ERR_OOM, + [LZW_OK_EOD] = NSGIF_ERR_END_OF_DATA, + [LZW_NO_DATA] = NSGIF_ERR_END_OF_DATA, + [LZW_EOI_CODE] = NSGIF_ERR_DATA_FRAME, + [LZW_BAD_ICODE] = NSGIF_ERR_DATA_FRAME, + [LZW_BAD_CODE] = NSGIF_ERR_DATA_FRAME, }; assert(l_res != LZW_BAD_PARAM); assert(l_res != LZW_NO_COLOUR); @@ -168,9 +176,9 @@ static nsgif_result nsgif__error_from_lzw(lzw_result l_res) * \param gif The animation context * \param width The width of the sprite * \param height The height of the sprite - * \return NSGIF_INSUFFICIENT_MEMORY for a memory error NSGIF_OK for success + * \return NSGIF_ERR_OOM for a memory error NSGIF_OK for success */ -static nsgif_result nsgif__initialise_sprite( +static nsgif_error nsgif__initialise_sprite( struct nsgif *gif, uint32_t width, uint32_t height) @@ -183,7 +191,7 @@ static nsgif_result nsgif__initialise_sprite( assert(gif->bitmap.create); gif->frame_image = gif->bitmap.create(width, height); if (gif->frame_image == NULL) { - return NSGIF_INSUFFICIENT_MEMORY; + return NSGIF_ERR_OOM; } return NSGIF_OK; @@ -198,7 +206,7 @@ static nsgif_result nsgif__initialise_sprite( static inline uint32_t* nsgif__bitmap_get( struct nsgif *gif) { - nsgif_result ret; + nsgif_error ret; /* Make sure we have a buffer to decode to. */ ret = nsgif__initialise_sprite(gif, gif->info.width, gif->info.height); @@ -292,7 +300,7 @@ static void nsgif__record_frame( gif->prev_index = gif->decoded_frame; } -static nsgif_result nsgif__recover_frame( +static nsgif_error nsgif__recover_frame( const struct nsgif *gif, uint32_t *bitmap) { @@ -300,10 +308,6 @@ static nsgif_result nsgif__recover_frame( unsigned height = gif->info.height; unsigned width = gif->info.width; - if (prev_frame == NULL) { - return NSGIF_FRAME_DATA_ERROR; - } - memcpy(bitmap, prev_frame, height * width * sizeof(*bitmap)); return NSGIF_OK; @@ -403,7 +407,7 @@ static inline void gif__jump_data( *pos += jump; } -static nsgif_result nsgif__decode_complex( +static nsgif_error nsgif__decode_complex( struct nsgif *gif, uint32_t width, uint32_t height, @@ -416,7 +420,7 @@ static nsgif_result nsgif__decode_complex( uint32_t *restrict colour_table) { lzw_result res; - nsgif_result ret = NSGIF_OK; + nsgif_error ret = NSGIF_OK; uint32_t clip_x = gif__clip(offset_x, width, gif->info.width); uint32_t clip_y = gif__clip(offset_y, height, gif->info.height); const uint8_t *uncompressed; @@ -502,7 +506,7 @@ static nsgif_result nsgif__decode_complex( return ret; } -static nsgif_result nsgif__decode_simple( +static nsgif_error nsgif__decode_simple( struct nsgif *gif, uint32_t height, uint32_t offset_y, @@ -513,7 +517,7 @@ static nsgif_result nsgif__decode_simple( { uint32_t pixels = gif->info.width * height; uint32_t written = 0; - nsgif_result ret = NSGIF_OK; + nsgif_error ret = NSGIF_OK; lzw_result res; if (offset_y >= gif->info.height) { @@ -560,7 +564,7 @@ static nsgif_result nsgif__decode_simple( return ret; } -static inline nsgif_result nsgif__decode( +static inline nsgif_error nsgif__decode( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t *data, @@ -570,7 +574,7 @@ static inline nsgif_result nsgif__decode( GIF_MASK_INTERLACE = 0x40, }; - nsgif_result ret; + nsgif_error ret; uint32_t width = frame->redraw.x1 - frame->redraw.x0; uint32_t height = frame->redraw.y1 - frame->redraw.y0; uint32_t offset_x = frame->redraw.x0; @@ -640,20 +644,20 @@ static void nsgif__restore_bg( } } -static nsgif_result nsgif__update_bitmap( +static nsgif_error nsgif__update_bitmap( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t *data, uint32_t frame_idx) { - nsgif_result ret; + nsgif_error ret; uint32_t *bitmap; gif->decoded_frame = frame_idx; bitmap = nsgif__bitmap_get(gif); if (bitmap == NULL) { - return NSGIF_INSUFFICIENT_MEMORY; + return NSGIF_ERR_OOM; } /* Handle any bitmap clearing/restoration required before decoding this @@ -700,10 +704,10 @@ static nsgif_result nsgif__update_bitmap( * \param[in] frame The gif object we're decoding. * \param[in] data The data to decode. * \param[in] len Byte length of data. - * \return NSGIF_INSUFFICIENT_DATA if more data is needed, + * \return NSGIF_ERR_END_OF_DATA if more data is needed, * NSGIF_OK for success. */ -static nsgif_result nsgif__parse_extension_graphic_control( +static nsgif_error nsgif__parse_extension_graphic_control( const struct nsgif *gif, struct nsgif_frame *frame, const uint8_t *data, @@ -727,7 +731,7 @@ static nsgif_result nsgif__parse_extension_graphic_control( * +5 CHAR Transparent Color Index */ if (len < 6) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } frame->frame_delay = data[3] | (data[4] << 8); @@ -766,10 +770,10 @@ static nsgif_result nsgif__parse_extension_graphic_control( * \param[in] gif The gif object we're decoding. * \param[in] data The data to decode. * \param[in] len Byte length of data. - * \return NSGIF_INSUFFICIENT_DATA if more data is needed, + * \return NSGIF_ERR_END_OF_DATA if more data is needed, * NSGIF_OK for success. */ -static nsgif_result nsgif__parse_extension_application( +static nsgif_error nsgif__parse_extension_application( struct nsgif *gif, const uint8_t *data, size_t len) @@ -783,7 +787,7 @@ static nsgif_result nsgif__parse_extension_application( * +13 1-256 Application Data (Data sub-blocks) */ if (len < 17) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } if ((data[1] == 0x0b) && @@ -802,10 +806,10 @@ static nsgif_result nsgif__parse_extension_application( * \param[in] frame The frame to parse extensions for. * \param[in] pos Current position in data, updated on exit. * \param[in] decode Whether to decode or skip over the extension. - * \return NSGIF_INSUFFICIENT_DATA if more data is needed, + * \return NSGIF_ERR_END_OF_DATA if more data is needed, * NSGIF_OK for success. */ -static nsgif_result nsgif__parse_frame_extensions( +static nsgif_error nsgif__parse_frame_extensions( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, @@ -825,13 +829,13 @@ static nsgif_result nsgif__parse_frame_extensions( /* Initialise the extensions */ while (nsgif_bytes > 0 && nsgif_data[0] == GIF_EXT_INTRODUCER) { bool block_step = true; - nsgif_result ret; + nsgif_error ret; nsgif_data++; nsgif_bytes--; if (nsgif_bytes == 0) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } /* Switch on extension label */ @@ -875,7 +879,7 @@ static nsgif_result nsgif__parse_frame_extensions( * the extension size itself */ if (nsgif_bytes < 2) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } nsgif_data += 2 + nsgif_data[1]; } @@ -885,7 +889,7 @@ static nsgif_result nsgif__parse_frame_extensions( while (nsgif_data < nsgif_end && nsgif_data[0] != NSGIF_BLOCK_TERMINATOR) { nsgif_data += nsgif_data[0] + 1; if (nsgif_data >= nsgif_end) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } } nsgif_data++; @@ -924,7 +928,7 @@ static nsgif_result nsgif__parse_frame_extensions( * \param[in] decode Whether to decode the image descriptor. * \return NSGIF_OK on success, appropriate error otherwise. */ -static nsgif_result nsgif__parse_image_descriptor( +static nsgif_error nsgif__parse_image_descriptor( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, @@ -941,14 +945,14 @@ static nsgif_result nsgif__parse_image_descriptor( assert(frame != NULL); if (len < NSGIF_IMAGE_DESCRIPTOR_LEN) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } if (decode) { uint32_t x, y, w, h; if (data[0] != NSGIF_IMAGE_SEPARATOR) { - return NSGIF_FRAME_DATA_ERROR; + return NSGIF_ERR_DATA_FRAME; } x = data[1] | (data[2] << 8); @@ -987,7 +991,7 @@ static nsgif_result nsgif__parse_image_descriptor( * \param[in] decode Whether to decode the colour table. * \return NSGIF_OK on success, appropriate error otherwise. */ -static nsgif_result nsgif__colour_table_extract( +static nsgif_error nsgif__colour_table_extract( struct nsgif *gif, uint32_t colour_table[NSGIF_MAX_COLOURS], size_t colour_table_entries, @@ -998,7 +1002,7 @@ static nsgif_result nsgif__colour_table_extract( size_t len = gif->nsgif_data + gif->buffer_size - data; if (len < colour_table_entries * 3) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } if (decode) { @@ -1036,13 +1040,13 @@ static nsgif_result nsgif__colour_table_extract( * \param[in] decode Whether to decode the colour table. * \return NSGIF_OK on success, appropriate error otherwise. */ -static nsgif_result nsgif__parse_colour_table( +static nsgif_error nsgif__parse_colour_table( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, bool decode) { - nsgif_result ret; + nsgif_error ret; assert(gif != NULL); assert(frame != NULL); @@ -1074,7 +1078,7 @@ static nsgif_result nsgif__parse_colour_table( * \param[in] decode Whether to decode the image data. * \return NSGIF_OK on success, appropriate error otherwise. */ -static nsgif_result nsgif__parse_image_data( +static nsgif_error nsgif__parse_image_data( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, @@ -1084,7 +1088,7 @@ static nsgif_result nsgif__parse_image_data( size_t len = gif->nsgif_data + gif->buffer_size - data; uint32_t frame_idx = frame - gif->frames; uint8_t minimum_code_size; - nsgif_result ret; + nsgif_error ret; assert(gif != NULL); assert(frame != NULL); @@ -1103,12 +1107,12 @@ static nsgif_result nsgif__parse_image_data( /* Fall through. */ case 1: if (data[0] == NSGIF_TRAILER) return NSGIF_OK; /* Fall through. */ - case 0: return NSGIF_INSUFFICIENT_DATA; + case 0: return NSGIF_ERR_END_OF_DATA; } minimum_code_size = data[0]; if (minimum_code_size >= LZW_CODE_MAX) { - return NSGIF_DATA_ERROR; + return NSGIF_ERR_DATA_FRAME; } if (decode) { @@ -1121,7 +1125,7 @@ static nsgif_result nsgif__parse_image_data( len--; while (block_size != 1) { - if (len < 1) return NSGIF_INSUFFICIENT_DATA; + if (len < 1) return NSGIF_ERR_END_OF_DATA; block_size = data[0] + 1; /* Check if the frame data runs off the end of the file */ if (block_size > len) { @@ -1133,20 +1137,12 @@ static nsgif_result nsgif__parse_image_data( data += block_size; } - gif->info.frame_count = frame_idx + 1; - gif->frames[frame_idx].display = true; *pos = data; - /* Check if we've finished */ - if (len < 1) { - return NSGIF_INSUFFICIENT_DATA; - } else { - if (data[0] == NSGIF_TRAILER) { - return NSGIF_OK; - } - } + gif->info.frame_count = frame_idx + 1; + gif->frames[frame_idx].display = true; - return NSGIF_WORKING; + return NSGIF_OK; } return ret; @@ -1193,27 +1189,21 @@ static struct nsgif_frame *nsgif__get_frame( * \param[in] gif The animation context * \param[in] frame_idx The frame number to decode. * \param[in] decode Whether to decode the graphical image data. - * \return error code - * - NSGIF_INSUFFICIENT_DATA reached unexpected end of source data. - * - NSGIF_FRAME_DATA_ERROR for GIF frame data error - * - NSGIF_INSUFFICIENT_MEMORY for insufficient memory to process - * - NSGIF_DATA_ERROR for GIF error (invalid frame header) - * - NSGIF_OK for successful decoding - * - NSGIF_WORKING for successful decoding if more frames are expected + * \return NSGIF_OK on success, appropriate error otherwise. */ -static nsgif_result nsgif__process_frame( +static nsgif_error nsgif__process_frame( struct nsgif *gif, uint32_t frame_idx, bool decode) { - nsgif_result ret; + nsgif_error ret; const uint8_t *pos; const uint8_t *end; struct nsgif_frame *frame; frame = nsgif__get_frame(gif, frame_idx); if (frame == NULL) { - return NSGIF_INSUFFICIENT_MEMORY; + return NSGIF_ERR_OOM; } end = gif->nsgif_data + gif->buffer_size; @@ -1228,7 +1218,7 @@ static nsgif_result nsgif__process_frame( /* Ensure the frame is in range to decode */ if (frame_idx > gif->frame_count_partial) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } /* Done if frame is already decoded */ @@ -1247,7 +1237,7 @@ static nsgif_result nsgif__process_frame( * millions of frames, so we ensure that we don't have a * silly number. */ if (frame_idx > 4096) { - return NSGIF_FRAME_DATA_ERROR; + return NSGIF_ERR_FRAME_COUNT; } } @@ -1306,13 +1296,13 @@ void nsgif_destroy(nsgif *gif) } /* exported function documented in nsgif.h */ -nsgif_result nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif **gif_out) +nsgif_error nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif **gif_out) { nsgif *gif; gif = calloc(1, sizeof(*gif)); if (gif == NULL) { - return NSGIF_INSUFFICIENT_MEMORY; + return NSGIF_ERR_OOM; } gif->bitmap = *bitmap_vt; @@ -1339,7 +1329,7 @@ nsgif_result nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif **gif_out) * \param[in] strict Whether to require a known GIF version. * \return NSGIF_OK on success, appropriate error otherwise. */ -static nsgif_result nsgif__parse_header( +static nsgif_error nsgif__parse_header( struct nsgif *gif, const uint8_t **pos, bool strict) @@ -1348,18 +1338,18 @@ static nsgif_result nsgif__parse_header( size_t len = gif->nsgif_data + gif->buffer_size - data; if (len < 6) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } if (strncmp((const char *) data, "GIF", 3) != 0) { - return NSGIF_DATA_ERROR; + return NSGIF_ERR_DATA; } data += 3; if (strict == true) { if ((strncmp((const char *) data, "87a", 3) != 0) && (strncmp((const char *) data, "89a", 3) != 0)) { - return NSGIF_DATA_ERROR; + return NSGIF_ERR_DATA; } } data += 3; @@ -1387,7 +1377,7 @@ static nsgif_result nsgif__parse_header( * \param[in,out] pos The current buffer position, updated on success. * \return NSGIF_OK on success, appropriate error otherwise. */ -static nsgif_result nsgif__parse_logical_screen_descriptor( +static nsgif_error nsgif__parse_logical_screen_descriptor( struct nsgif *gif, const uint8_t **pos) { @@ -1395,7 +1385,7 @@ static nsgif_result nsgif__parse_logical_screen_descriptor( size_t len = gif->nsgif_data + gif->buffer_size - data; if (len < 7) { - return NSGIF_INSUFFICIENT_DATA; + return NSGIF_ERR_END_OF_DATA; } gif->info.width = data[0] | (data[1] << 8); @@ -1411,13 +1401,14 @@ static nsgif_result nsgif__parse_logical_screen_descriptor( } /* exported function documented in nsgif.h */ -nsgif_result nsgif_data_scan( +nsgif_error nsgif_data_scan( nsgif *gif, size_t size, const uint8_t *data) { const uint8_t *nsgif_data; - nsgif_result ret; + nsgif_error ret; + uint32_t frames; /* Initialize values */ gif->buffer_size = size; @@ -1533,10 +1524,16 @@ nsgif_result nsgif_data_scan( } } - /* Repeatedly try to initialise frames */ + /* Try to initialise all frames. */ do { - ret = nsgif__process_frame(gif, gif->info.frame_count, false); - } while (ret == NSGIF_WORKING); + frames = gif->info.frame_count; + ret = nsgif__process_frame(gif, frames, false); + } while (gif->info.frame_count > frames); + + if (ret == NSGIF_ERR_END_OF_DATA && + gif->info.frame_count > 0) { + ret = NSGIF_ERR_END_OF_FRAME; + } return ret; } @@ -1578,7 +1575,7 @@ static uint32_t nsgif__frame_next( return (frame >= frames) ? 0 : frame; } -static nsgif_result nsgif__next_displayable_frame( +static nsgif_error nsgif__next_displayable_frame( nsgif *gif, uint32_t *frame, uint32_t *delay) @@ -1588,7 +1585,7 @@ static nsgif_result nsgif__next_displayable_frame( do { next = nsgif__frame_next(gif, false, next); if (next == *frame || next == NSGIF_FRAME_INVALID) { - return NSGIF_FRAME_NO_DISPLAY; + return NSGIF_ERR_FRAME_DISPLAY; } if (delay != NULL) { @@ -1610,7 +1607,7 @@ static inline bool nsgif__animation_complete(int count, int max) return (count >= max); } -nsgif_result nsgif_reset( +nsgif_error nsgif_reset( nsgif *gif) { gif->info.loop_count = 0; @@ -1620,13 +1617,13 @@ nsgif_result nsgif_reset( } /* exported function documented in nsgif.h */ -nsgif_result nsgif_frame_prepare( +nsgif_error nsgif_frame_prepare( nsgif *gif, nsgif_rect *area, uint32_t *delay_cs, uint32_t *frame_new) { - nsgif_result ret; + nsgif_error ret; nsgif_rect rect = { .x1 = 0, .y1 = 0, @@ -1645,7 +1642,7 @@ nsgif_result nsgif_frame_prepare( if (nsgif__animation_complete( gif->info.loop_count, gif->info.loop_max)) { - return NSGIF_ANIMATION_COMPLETE; + return NSGIF_ERR_ANIMATION_END; } ret = nsgif__next_displayable_frame(gif, &frame, NULL); @@ -1682,13 +1679,17 @@ nsgif_result nsgif_frame_prepare( } /* exported function documented in nsgif.h */ -nsgif_result nsgif_frame_decode( +nsgif_error nsgif_frame_decode( nsgif *gif, uint32_t frame, nsgif_bitmap_t **bitmap) { uint32_t start_frame; - nsgif_result ret = NSGIF_OK; + nsgif_error ret = NSGIF_OK; + + if (frame > gif->info.frame_count) { + return NSGIF_ERR_BAD_FRAME; + } if (gif->decoded_frame == frame) { *bitmap = gif->frame_image; @@ -1718,3 +1719,26 @@ const nsgif_info_t *nsgif_get_info(const nsgif *gif) { return &gif->info; } + +/* exported function documented in nsgif.h */ +const char *nsgif_strerror(nsgif_error err) +{ + static const char *const str[] = { + [NSGIF_OK] = "Success", + [NSGIF_ERR_OOM] = "Out of memory", + [NSGIF_ERR_DATA] = "Invalid source data", + [NSGIF_ERR_BAD_FRAME] = "Requested frame does not exist", + [NSGIF_ERR_DATA_FRAME] = "Invalid frame data", + [NSGIF_ERR_FRAME_COUNT] = "Excessive number of frames", + [NSGIF_ERR_END_OF_DATA] = "Insufficient data for first frame", + [NSGIF_ERR_END_OF_FRAME] = "End of data during frame", + [NSGIF_ERR_FRAME_DISPLAY] = "Frame can't be displayed", + [NSGIF_ERR_ANIMATION_END] = "Animation complete", + }; + + if (err >= NSGIF_ARRAY_LEN(str) || str[err] == NULL) { + return "Unknown error"; + } + + return str[err]; +} diff --git a/test/decode_gif.c b/test/decode_gif.c index acc2ef0..173f70c 100644 --- a/test/decode_gif.c +++ b/test/decode_gif.c @@ -78,32 +78,15 @@ static uint8_t *load_file(const char *path, size_t *data_size) return buffer; } -static void warning(const char *context, nsgif_result gif_res) +static void warning(const char *context, nsgif_error err) { - fprintf(stderr, "%s failed: ", context); - switch (gif_res) { - case NSGIF_FRAME_DATA_ERROR: - fprintf(stderr, "NSGIF_FRAME_DATA_ERROR"); - break; - case NSGIF_INSUFFICIENT_DATA: - fprintf(stderr, "NSGIF_INSUFFICIENT_DATA"); - break; - case NSGIF_DATA_ERROR: - fprintf(stderr, "NSGIF_DATA_ERROR"); - break; - case NSGIF_INSUFFICIENT_MEMORY: - fprintf(stderr, "NSGIF_INSUFFICIENT_MEMORY"); - break; - default: - fprintf(stderr, "unknown code %i", gif_res); - break; - } - fprintf(stderr, "\n"); + fprintf(stderr, "%s failed: %s\n", + context, nsgif_strerror(err)); } static void decode(FILE* fh, const char *name, nsgif *gif, bool write_ppm) { - nsgif_result gif_res; + nsgif_error err; uint32_t frame_prev = 0; const nsgif_info_t *info; @@ -128,10 +111,10 @@ static void decode(FILE* fh, const char *name, nsgif *gif, bool write_ppm) uint32_t delay_cs; nsgif_rect area; - gif_res = nsgif_frame_prepare(gif, &area, + err = nsgif_frame_prepare(gif, &area, &delay_cs, &frame_new); - if (gif_res != NSGIF_OK) { - warning("nsgif_frame_prepare", gif_res); + if (err != NSGIF_OK) { + warning("nsgif_frame_prepare", err); return; } @@ -142,9 +125,9 @@ static void decode(FILE* fh, const char *name, nsgif *gif, bool write_ppm) } frame_prev = frame_new; - gif_res = nsgif_frame_decode(gif, frame_new, &buffer); - if (gif_res != NSGIF_OK) { - warning("nsgif_decode_frame", gif_res); + err = nsgif_frame_decode(gif, frame_new, &buffer); + if (err != NSGIF_OK) { + warning("nsgif_decode_frame", err); return; } @@ -175,8 +158,8 @@ int main(int argc, char *argv[]) nsgif *gif; size_t size; uint8_t *data; + nsgif_error err; FILE *outf = stdout; - nsgif_result gif_res; bool no_write = false; if (argc < 2) { @@ -203,8 +186,8 @@ int main(int argc, char *argv[]) } /* create our gif animation */ - gif_res = nsgif_create(&bitmap_callbacks, &gif); - if (gif_res != NSGIF_OK) { + err = nsgif_create(&bitmap_callbacks, &gif); + if (err != NSGIF_OK) { return 1; } @@ -212,9 +195,9 @@ int main(int argc, char *argv[]) data = load_file(argv[1], &size); /* Scan the raw data */ - gif_res = nsgif_data_scan(gif, size, data); - if (gif_res != NSGIF_OK) { - warning("nsgif_data_scan", gif_res); + err = nsgif_data_scan(gif, size, data); + if (err != NSGIF_OK) { + warning("nsgif_data_scan", err); nsgif_destroy(gif); free(data); return 1; |