Improve '__read_gif()' function to reduce Cyclomatic Complexity 22/214822/4
authorjiyong.min <jiyong.min@samsung.com>
Fri, 27 Sep 2019 00:41:29 +0000 (09:41 +0900)
committerjiyong.min <jiyong.min@samsung.com>
Tue, 1 Oct 2019 02:13:25 +0000 (11:13 +0900)
Change-Id: I1551e9c5019fcdb74aa7defb74ceb2245f823316

gif/mm_util_gif.c

index 310ff5d..7e69fae 100644 (file)
@@ -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;