From: jiyong.min Date: Fri, 27 Sep 2019 00:41:29 +0000 (+0900) Subject: Improve '__read_gif()' function to reduce Cyclomatic Complexity X-Git-Tag: accepted/tizen/5.5/unified/20191031.021526~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3368cc9bb692a99e07420e77aa97f7649ee17d0f;p=platform%2Fcore%2Fmultimedia%2Flibmm-utility.git Improve '__read_gif()' function to reduce Cyclomatic Complexity Change-Id: I1551e9c5019fcdb74aa7defb74ceb2245f823316 --- diff --git a/gif/mm_util_gif.c b/gif/mm_util_gif.c index 310ff5d..7e69fae 100644 --- a/gif/mm_util_gif.c +++ b/gif/mm_util_gif.c @@ -48,34 +48,6 @@ typedef struct { gif_io_buf_s io_buf; } gif_file_s; -static int __convert_gif_to_rgba(void **data, ColorMapObject *color_map, GifRowType *screen_buffer, unsigned int width, unsigned int height) -{ - unsigned long i, j; - GifRowType gif_row; - GifColorType *color_map_entry; - GifByteType *buffer; - - mm_util_fenter(); - - if ((*data = (void *)calloc(1, width * height * 4)) == NULL) { - mm_util_error("Failed to allocate memory required, aborted."); - return MM_UTIL_ERROR_OUT_OF_MEMORY; - } - - buffer = (GifByteType *) *data; - for (i = 0; i < height; i++) { - gif_row = screen_buffer[i]; - for (j = 0; j < width; j++) { - color_map_entry = &color_map->Colors[gif_row[j]]; - *buffer++ = color_map_entry->Red; - *buffer++ = color_map_entry->Green; - *buffer++ = color_map_entry->Blue; - *buffer++ = 255; - } - } - return MM_UTIL_ERROR_NONE; -} - static int __read_function(GifFileType *gft, GifByteType *data, int size) { gif_io_buf_s *io_buf = (gif_io_buf_s *) gft->UserData; @@ -91,148 +63,242 @@ static int __read_function(GifFileType *gft, GifByteType *data, int size) return size; } -static int __read_gif(const char *file_path, void *memory, const size_t src_size, mm_util_image_h *decoded) +static int __gif_open(const char *file_path, void *memory, const size_t src_size, gif_io_buf_s *io_buf, GifFileType **gif_image) { - int ret = MM_UTIL_ERROR_NONE; - - int ExtCode, i, j, Row, Col, Width, Height; - size_t Size = 0; - GifRecordType record_type; - GifRowType *screen_buffer = NULL; - GifFileType *GifFile; - unsigned int image_num = 0; - ColorMapObject *ColorMap; - gif_io_buf_s io_buf = { memory, src_size, 0 }; - void *_data = NULL; - mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path) && (memory == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid gif image"); - mm_util_retvm_if(!decoded, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image handle"); - - mm_util_fenter(); if (MMUTIL_STRING_VALID(file_path)) { mm_util_sec_debug("read from file [%s]", file_path); - if ((GifFile = DGifOpenFileName(file_path, NULL)) == NULL) { + if ((*gif_image = DGifOpenFileName(file_path, NULL)) == NULL) { mm_util_error("could not open Gif File"); return MM_UTIL_ERROR_INVALID_OPERATION; } } else { mm_util_debug("read from memory"); - if ((GifFile = DGifOpen(&io_buf, __read_function, NULL)) == NULL) { + if ((*gif_image = DGifOpen(io_buf, __read_function, NULL)) == NULL) { mm_util_error("could not open Gif File"); return MM_UTIL_ERROR_INVALID_OPERATION; } } - if (GifFile->SWidth <= 0 || GifFile->SHeight <= 0) { - mm_util_error("Gif File wrong decode width & height"); + return MM_UTIL_ERROR_NONE; +} + +static void __gif_free_frame_buffer(GifRowType *frame_buffer, unsigned int size) +{ + int idx = 0; + + if (!frame_buffer) + return; + + for (idx = 0; idx < (int)size; idx++) + MMUTIL_SAFE_FREE(frame_buffer[idx]); + free(frame_buffer); +} + +static int __gif_generate_frame_buffer(GifFileType *gif_image, GifRowType **screen_buf) +{ + int idx = 0; + size_t row_size = 0; + GifRowType* _screen_buf = NULL; + + _screen_buf = (GifRowType *)calloc(1, gif_image->SHeight * sizeof(GifRowType)); + mm_util_retvm_if(!_screen_buf, MM_UTIL_ERROR_OUT_OF_MEMORY, "Failed to allocate memory required, aborted."); + + row_size = gif_image->SWidth * sizeof(GifPixelType); /* Size in bytes one row. */ + if ((_screen_buf[0] = (GifRowType) calloc(1, row_size)) == NULL) { /* First row. */ + mm_util_error("Failed to allocate memory required, aborted."); + MMUTIL_SAFE_FREE(_screen_buf); return MM_UTIL_ERROR_INVALID_OPERATION; } - if ((screen_buffer = (GifRowType *)calloc(1, GifFile->SHeight * sizeof(GifRowType))) == NULL) { - mm_util_error("Failed to allocate memory required, aborted."); - ret = MM_UTIL_ERROR_INVALID_OPERATION; - goto error; + for (idx = 0; idx < (int)(gif_image->SWidth); idx++) /* Set its color to BackGround. */ + _screen_buf[0][idx] = gif_image->SBackGroundColor; + + for (idx = 1; idx < (int)(gif_image->SHeight); idx++) { + /* Allocate the other rows, and set their color to background too: */ + if ((_screen_buf[idx] = (GifRowType) calloc(1, row_size)) == NULL) { + mm_util_error("Failed to allocate memory required, aborted."); + __gif_free_frame_buffer(_screen_buf, idx - 1); + return MM_UTIL_ERROR_INVALID_OPERATION; + } + + memcpy(_screen_buf[idx], _screen_buf[0], row_size); } - Size = GifFile->SWidth * sizeof(GifPixelType); /* Size in bytes one row. */ - if ((screen_buffer[0] = (GifRowType) calloc(1, Size)) == NULL) { /* First row. */ + *screen_buf = _screen_buf; + + return MM_UTIL_ERROR_NONE; +} + +static gboolean __gif_is_good_frame(GifFileType *gif_image) +{ + mm_util_debug("Frame pos: %d, %d size: %dx%d", gif_image->Image.Left, gif_image->Image.Top, gif_image->Image.Width, gif_image->Image.Height); + + if (gif_image->Image.Top < 0 || gif_image->Image.Left < 0 || gif_image->Image.Width <= 0 || gif_image->Image.Height <= 0) { + mm_util_error("Frame has wrong dimensions"); + return FALSE; + } + + if (gif_image->Image.Left + gif_image->Image.Width > gif_image->SWidth || gif_image->Image.Top + gif_image->Image.Height > gif_image->SHeight) { + mm_util_debug("Frame is not full screen frame"); + return FALSE; + } + + return TRUE; +} + +static int __gif_fill_frame_buffer(GifFileType *gif_image, GifRowType *frame_buffer) +{ + unsigned int i, j; + + unsigned int Row = (unsigned int)gif_image->Image.Top; /* Image Position relative to Screen. */ + unsigned int Col = (unsigned int)gif_image->Image.Left; + unsigned int Width = (unsigned int)gif_image->Image.Width; + unsigned int Height = (unsigned int)gif_image->Image.Height; + unsigned int interlaced_offset[] = { 0, 4, 2, 1 }, interlaced_jumps[] = { + 8, 8, 4, 2}; + + if (gif_image->Image.Interlace) { + /* Need to perform 4 passes on the images: */ + for (i = 0; i < 4; i++) + for (j = Row + interlaced_offset[i]; j < Row + Height; j += interlaced_jumps[i]) { + if (DGifGetLine(gif_image, &frame_buffer[j][Col], Width) == GIF_ERROR) { + mm_util_error("could not get line (%u)", gif_image->Error); + return MM_UTIL_ERROR_INVALID_OPERATION; + } + } + } else { + for (i = 0; i < Height; i++) { + if (DGifGetLine(gif_image, &frame_buffer[Row++][Col], Width) == GIF_ERROR) { + mm_util_error("could not get line (%u)", gif_image->Error); + return MM_UTIL_ERROR_INVALID_OPERATION; + } + } + } + + return MM_UTIL_ERROR_NONE; +} + +static int __gif_get_extension(GifFileType *gif_image) +{ + int ExtCode = 0; + GifByteType *extension = NULL; + + /* for skip any extension blocks in file */ + if (DGifGetExtension(gif_image, &ExtCode, &extension) == GIF_ERROR) { + mm_util_error("could not get extension (%u)", gif_image->Error); + return MM_UTIL_ERROR_INVALID_OPERATION; + } + while (extension != NULL) { + if (DGifGetExtensionNext(gif_image, &extension) == GIF_ERROR) { + mm_util_error("could not get next extension (%u)", gif_image->Error); + return MM_UTIL_ERROR_INVALID_OPERATION; + } + } + + return MM_UTIL_ERROR_NONE; +} + +static int __gif_convert_to_rgba(void **data, ColorMapObject *color_map, GifRowType *frame_buffer, unsigned int width, unsigned int height) +{ + unsigned int i, j; + GifRowType gif_row; + GifColorType *color_map_entry; + GifByteType *buffer; + + mm_util_fenter(); + + if ((*data = (void *)calloc(1, width * height * 4)) == NULL) { mm_util_error("Failed to allocate memory required, aborted."); - ret = MM_UTIL_ERROR_INVALID_OPERATION; - goto error; + return MM_UTIL_ERROR_OUT_OF_MEMORY; } - for (i = 0; i < (int)(GifFile->SWidth); i++) /* Set its color to BackGround. */ - screen_buffer[0][i] = GifFile->SBackGroundColor; - for (i = 1; i < (int)(GifFile->SHeight); i++) { - /* Allocate the other rows, and set their color to background too: */ - if ((screen_buffer[i] = (GifRowType) calloc(1, Size)) == NULL) { - mm_util_error("Failed to allocate memory required, aborted."); - ret = MM_UTIL_ERROR_INVALID_OPERATION; - goto error; + buffer = (GifByteType *) *data; + for (i = 0; i < height; i++) { + gif_row = frame_buffer[i]; + for (j = 0; j < width; j++) { + color_map_entry = &color_map->Colors[gif_row[j]]; + *buffer++ = color_map_entry->Red; + *buffer++ = color_map_entry->Green; + *buffer++ = color_map_entry->Blue; + *buffer++ = 255; } + } + + return MM_UTIL_ERROR_NONE; +} + +static int __read_gif(const char *file_path, void *memory, const size_t src_size, mm_util_image_h *decoded) +{ + int ret = MM_UTIL_ERROR_NONE; + + GifRecordType record_type = UNDEFINED_RECORD_TYPE; + GifRowType *frame_buffer = NULL; + GifFileType *GifFile; + gboolean is_found = FALSE; + ColorMapObject *ColorMap = NULL; + gif_io_buf_s io_buf = { memory, src_size, 0 }; + void *image_buffer = NULL; + + mm_util_retvm_if(!decoded, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image handle"); + + mm_util_fenter(); - memcpy(screen_buffer[i], screen_buffer[0], Size); + ret = __gif_open(file_path, memory, src_size, &io_buf, &GifFile); + mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_open failed"); + + mm_util_retvm_if(GifFile->SWidth <= 0 || GifFile->SHeight <= 0, MM_UTIL_ERROR_INVALID_OPERATION, "Gif File wrong decode width & height"); + + ret = __gif_generate_frame_buffer(GifFile, &frame_buffer); + if (ret != MM_UTIL_ERROR_NONE) { + mm_util_debug("__gif_generate_frame_buffer failed"); + goto error; } /* Scan the content of the GIF file and load the image(s) in: */ do { if (DGifGetRecordType(GifFile, &record_type) == GIF_ERROR) { - mm_util_error("could not get record type"); + mm_util_error("could not get record type (%u)", GifFile->Error); ret = MM_UTIL_ERROR_INVALID_OPERATION; goto error; } switch (record_type) { case IMAGE_DESC_RECORD_TYPE: + /* get frame data */ if (DGifGetImageDesc(GifFile) == GIF_ERROR) { mm_util_error("could not get image description"); ret = MM_UTIL_ERROR_INVALID_OPERATION; goto error; } - if (GifFile->Image.Top < 0 || GifFile->Image.Left < 0 || GifFile->Image.Width <= 0 || GifFile->Image.Height <= 0) { - mm_util_error("Gif File wrong decode width & height"); + + if (!__gif_is_good_frame(GifFile)) { + mm_util_debug("Image is not confined to screen dimension, aborted."); ret = MM_UTIL_ERROR_INVALID_OPERATION; goto error; } - Row = GifFile->Image.Top; /* Image Position relative to Screen. */ - Col = GifFile->Image.Left; - Width = GifFile->Image.Width; - Height = GifFile->Image.Height; - mm_util_debug("Image %d at (%d, %d) [%dx%d]", image_num + 1, Col, Row, Width, Height); - if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth || GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) { - mm_util_debug("Image %d is not confined to screen dimension, aborted.", image_num + 1); - ret = MM_UTIL_ERROR_INVALID_OPERATION; + + is_found = TRUE; + + ret = __gif_fill_frame_buffer(GifFile, frame_buffer); + if (ret != MM_UTIL_ERROR_NONE) { + mm_util_error("__gif_generate_frame_buffer failed"); goto error; } - image_num++; - if (GifFile->Image.Interlace) { - int interlaced_offset[] = { 0, 4, 2, 1 }, interlaced_jumps[] = { - 8, 8, 4, 2}; - /* Need to perform 4 passes on the images: */ - for (i = 0; i < 4; i++) - for (j = Row + interlaced_offset[i]; j < Row + Height; j += interlaced_jumps[i]) { - if (DGifGetLine(GifFile, &screen_buffer[j][Col], Width) == GIF_ERROR) { - mm_util_error("could not get line"); - ret = MM_UTIL_ERROR_INVALID_OPERATION; - goto error; - } - } - } else { - for (i = 0; i < Height; i++) { - if (DGifGetLine(GifFile, &screen_buffer[Row++][Col], Width) == GIF_ERROR) { - mm_util_error("could not get line"); - ret = MM_UTIL_ERROR_INVALID_OPERATION; - goto error; - } - } - } break; case EXTENSION_RECORD_TYPE: - { - GifByteType *extension; - /* Skip any extension blocks in file: */ - if (DGifGetExtension(GifFile, &ExtCode, &extension) == GIF_ERROR) { - mm_util_error("could not get extension"); - ret = MM_UTIL_ERROR_INVALID_OPERATION; - goto error; - } - while (extension != NULL) { - if (DGifGetExtensionNext(GifFile, &extension) == GIF_ERROR) { - mm_util_error("could not get next extension"); - ret = MM_UTIL_ERROR_INVALID_OPERATION; - goto error; - } - } - } + /* currently, we don't use extension value, it needs to play animation */ + ret = __gif_get_extension(GifFile); + if (ret != MM_UTIL_ERROR_NONE) + goto error; break; case TERMINATE_RECORD_TYPE: break; - default: /* Should be trapped by DGifGetRecordType. */ + default: + /* should be trapped by DGifGetRecordType. */ break; } - if (image_num > 0) - break; - } while (record_type != TERMINATE_RECORD_TYPE); + } while (record_type != TERMINATE_RECORD_TYPE && !is_found); ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap); if (ColorMap == NULL) { @@ -241,26 +307,20 @@ static int __read_gif(const char *file_path, void *memory, const size_t src_size goto error; } - ret = __convert_gif_to_rgba(&_data, ColorMap, screen_buffer, GifFile->SWidth, GifFile->SHeight); + /* decompress image with colormap(256) */ + ret = __gif_convert_to_rgba(&image_buffer, ColorMap, frame_buffer, GifFile->SWidth, GifFile->SHeight); if (ret != MM_UTIL_ERROR_NONE) { mm_util_error("could not convert gif to rgba"); ret = MM_UTIL_ERROR_INVALID_OPERATION; goto error; } - ret = mm_image_create_image(GifFile->SWidth, GifFile->SHeight, MM_UTIL_COLOR_RGBA, _data, GifFile->SWidth * GifFile->SHeight * 4, decoded); - MMUTIL_SAFE_FREE(_data); + ret = mm_image_create_image(GifFile->SWidth, GifFile->SHeight, MM_UTIL_COLOR_RGBA, image_buffer, GifFile->SWidth * GifFile->SHeight * 4, decoded); + MMUTIL_SAFE_FREE(image_buffer); error: - if (screen_buffer) { - if (screen_buffer[0]) - (void)free(screen_buffer[0]); - for (i = 1; i < (int)(GifFile->SHeight); i++) { - if (screen_buffer[i]) - (void)free(screen_buffer[i]); - } - (void)free(screen_buffer); - } + __gif_free_frame_buffer(frame_buffer, GifFile->SHeight); + if (DGifCloseFile(GifFile, NULL) == GIF_ERROR) { mm_util_error("could not close file"); ret = MM_UTIL_ERROR_INVALID_OPERATION;