Update GIFLIB to 5.1.4 DO NOT MERGE am: 160402694e am: b9d1aac7b6 -s ours am: 54529030eb am: 271553a9ab am: 1813909837
am: cd2f4359e0 -s ours
Change-Id: I39f8697727bb6afca142db734af5459b2762851c
diff --git a/Android.mk b/Android.mk
index 427c1ee..437a8f7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -4,15 +4,15 @@
LOCAL_SDK_VERSION := 9
LOCAL_SRC_FILES := \
- dgif_lib.c \
- egif_lib.c \
- gifalloc.c \
- gif_err.c \
- gif_hash.c \
- quantize.c
+ dgif_lib.c \
+ egif_lib.c \
+ gifalloc.c \
+ gif_err.c \
+ gif_hash.c \
+ openbsd-reallocarray.c \
+ quantize.c
LOCAL_CFLAGS += -Wno-format -Wno-sign-compare -Wno-unused-parameter -DHAVE_CONFIG_H
-LOCAL_SDK_VERSION := 8
LOCAL_MODULE:= libgif
include $(BUILD_STATIC_LIBRARY)
diff --git a/README.version b/README.version
new file mode 100644
index 0000000..8d84679
--- /dev/null
+++ b/README.version
@@ -0,0 +1,3 @@
+URL: https://sourceforge.net/projects/giflib/files/giflib-5.1.1.tar.bz2/download
+Version: 5.1.1
+BugComponent: 24950
diff --git a/dgif_lib.c b/dgif_lib.c
index 744a2f9..66a1d6a 100644
--- a/dgif_lib.c
+++ b/dgif_lib.c
@@ -59,7 +59,6 @@
}
GifFile = DGifOpenFileHandle(FileHandle, Error);
- // cppcheck-suppress resourceLeak
return GifFile;
}
@@ -90,7 +89,7 @@
GifFile->SavedImages = NULL;
GifFile->SColorMap = NULL;
- Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
+ Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
if (Private == NULL) {
if (Error != NULL)
*Error = D_GIF_ERR_NOT_ENOUGH_MEM;
@@ -98,6 +97,9 @@
free((char *)GifFile);
return NULL;
}
+
+ /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
+
#ifdef _WIN32
_setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
#endif /* _WIN32 */
@@ -114,6 +116,7 @@
/*@=mustfreeonly@*/
/* Let's see if this is a GIF file: */
+ /* coverity[check_return] */
if (READ(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {
if (Error != NULL)
*Error = D_GIF_ERR_READ_FAILED;
@@ -172,13 +175,14 @@
GifFile->SavedImages = NULL;
GifFile->SColorMap = NULL;
- Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
+ Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
if (!Private) {
if (Error != NULL)
*Error = D_GIF_ERR_NOT_ENOUGH_MEM;
free((char *)GifFile);
return NULL;
}
+ /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
GifFile->Private = (void *)Private;
Private->FileHandle = 0;
@@ -189,6 +193,7 @@
GifFile->UserData = userData; /* TVT */
/* Lets see if this is a GIF file: */
+ /* coverity[check_return] */
if (READ(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {
if (Error != NULL)
*Error = D_GIF_ERR_READ_FAILED;
@@ -210,6 +215,8 @@
if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
free((char *)Private);
free((char *)GifFile);
+ if (Error != NULL)
+ *Error = D_GIF_ERR_NO_SCRN_DSCR;
return NULL;
}
@@ -267,6 +274,7 @@
/* Get the global color map: */
GifFile->SColorMap->SortFlag = SortFlag;
for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
+ /* coverity[check_return] */
if (READ(GifFile, Buf, 3) != 3) {
GifFreeMapObject(GifFile->SColorMap);
GifFile->SColorMap = NULL;
@@ -299,6 +307,7 @@
return GIF_ERROR;
}
+ /* coverity[check_return] */
if (READ(GifFile, &Buf, 1) != 1) {
GifFile->Error = D_GIF_ERR_READ_FAILED;
return GIF_ERROR;
@@ -372,6 +381,7 @@
/* Get the image local color map: */
for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
+ /* coverity[check_return] */
if (READ(GifFile, Buf, 3) != 3) {
GifFreeMapObject(GifFile->Image.ColorMap);
GifFile->Error = D_GIF_ERR_READ_FAILED;
@@ -385,12 +395,14 @@
}
if (GifFile->SavedImages) {
- if ((GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
- sizeof(SavedImage) *
- (GifFile->ImageCount + 1))) == NULL) {
+ SavedImage* new_saved_images =
+ (SavedImage *)reallocarray(GifFile->SavedImages,
+ (GifFile->ImageCount + 1), sizeof(SavedImage));
+ if (new_saved_images == NULL) {
GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
return GIF_ERROR;
}
+ GifFile->SavedImages = new_saved_images;
} else {
if ((GifFile->SavedImages =
(SavedImage *) malloc(sizeof(SavedImage))) == NULL) {
@@ -420,9 +432,7 @@
(long)GifFile->Image.Height;
/* Reset decompress algorithm parameters. */
- (void)DGifSetupDecompress(GifFile);
-
- return GIF_OK;
+ return DGifSetupDecompress(GifFile);
}
/******************************************************************************
@@ -521,6 +531,7 @@
return GIF_ERROR;
}
+ /* coverity[check_return] */
if (READ(GifFile, &Buf, 1) != 1) {
GifFile->Error = D_GIF_ERR_READ_FAILED;
return GIF_ERROR;
@@ -548,7 +559,7 @@
if (Buf > 0) {
*Extension = Private->Buf; /* Use private unused buffer. */
(*Extension)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
- /* coverity[tainted_data] */
+ /* coverity[tainted_data,check_return] */
if (READ(GifFile, &((*Extension)[1]), Buf) != Buf) {
GifFile->Error = D_GIF_ERR_READ_FAILED;
return GIF_ERROR;
@@ -612,7 +623,7 @@
This routine should be called last, to close the GIF file.
******************************************************************************/
int
-DGifCloseFile(GifFileType *GifFile)
+DGifCloseFile(GifFileType *GifFile, int *ErrorCode)
{
GifFilePrivateType *Private;
@@ -640,25 +651,25 @@
if (!IS_READABLE(Private)) {
/* This file was NOT open for reading: */
- GifFile->Error = D_GIF_ERR_NOT_READABLE;
+ if (ErrorCode != NULL)
+ *ErrorCode = D_GIF_ERR_NOT_READABLE;
+ free((char *)GifFile->Private);
+ free(GifFile);
return GIF_ERROR;
}
if (Private->File && (fclose(Private->File) != 0)) {
- GifFile->Error = D_GIF_ERR_CLOSE_FAILED;
+ if (ErrorCode != NULL)
+ *ErrorCode = D_GIF_ERR_CLOSE_FAILED;
+ free((char *)GifFile->Private);
+ free(GifFile);
return GIF_ERROR;
}
free((char *)GifFile->Private);
-
- /*
- * Without the #ifndef, we get spurious warnings because Coverity mistakenly
- * thinks the GIF structure is freed on an error return.
- */
-#ifndef __COVERITY__
free(GifFile);
-#endif /* __COVERITY__ */
-
+ if (ErrorCode != NULL)
+ *ErrorCode = D_GIF_SUCCEEDED;
return GIF_OK;
}
@@ -670,6 +681,7 @@
{
unsigned char c[2];
+ /* coverity[check_return] */
if (READ(GifFile, c, 2) != 2) {
GifFile->Error = D_GIF_ERR_READ_FAILED;
return GIF_ERROR;
@@ -714,6 +726,7 @@
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
/* coverity[tainted_data_argument] */
+ /* coverity[check_return] */
if (READ(GifFile, &Buf, 1) != 1) {
GifFile->Error = D_GIF_ERR_READ_FAILED;
return GIF_ERROR;
@@ -748,9 +761,18 @@
GifPrefixType *Prefix;
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
- READ(GifFile, &CodeSize, 1); /* Read Code size from file. */
+ /* coverity[check_return] */
+ if (READ(GifFile, &CodeSize, 1) < 1) { /* Read Code size from file. */
+ return GIF_ERROR; /* Failed to read Code size. */
+ }
BitsPerPixel = CodeSize;
+ /* this can only happen on a severely malformed GIF */
+ if (BitsPerPixel > 8) {
+ GifFile->Error = D_GIF_ERR_READ_FAILED; /* somewhat bogus error code */
+ return GIF_ERROR; /* Failed to read Code size. */
+ }
+
Private->Buf[0] = 0; /* Input Buffer empty. */
Private->BitsPerPixel = BitsPerPixel;
Private->ClearCode = (1 << BitsPerPixel);
@@ -834,19 +856,22 @@
* pixels on our stack. If we done, pop the stack in reverse
* (thats what stack is good for!) order to output. */
if (Prefix[CrntCode] == NO_SUCH_CODE) {
+ CrntPrefix = LastCode;
+
/* Only allowed if CrntCode is exactly the running code:
* In that case CrntCode = XXXCode, CrntCode or the
* prefix code is last code and the suffix char is
* exactly the prefix of last code! */
if (CrntCode == Private->RunningCode - 2) {
- CrntPrefix = LastCode;
Suffix[Private->RunningCode - 2] =
Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
LastCode,
ClearCode);
} else {
- GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
- return GIF_ERROR;
+ Suffix[Private->RunningCode - 2] =
+ Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
+ CrntCode,
+ ClearCode);
}
} else
CrntPrefix = CrntCode;
@@ -1018,6 +1043,7 @@
{
if (Buf[0] == 0) {
/* Needs to read the next buffer - this one is empty: */
+ /* coverity[check_return] */
if (READ(GifFile, Buf, 1) != 1) {
GifFile->Error = D_GIF_ERR_READ_FAILED;
return GIF_ERROR;
@@ -1030,14 +1056,6 @@
GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
return GIF_ERROR;
}
- /* There shouldn't be any empty data blocks here as the LZW spec
- * says the LZW termination code should come first. Therefore we
- * shouldn't be inside this routine at that point.
- */
- if (Buf[0] == 0) {
- GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
- return GIF_ERROR;
- }
if (READ(GifFile, &Buf[1], Buf[0]) != Buf[0]) {
GifFile->Error = D_GIF_ERR_READ_FAILED;
return GIF_ERROR;
@@ -1090,7 +1108,7 @@
if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
return GIF_ERROR;
}
- sp->RasterBits = (unsigned char *)malloc(ImageSize *
+ sp->RasterBits = (unsigned char *)reallocarray(NULL, ImageSize,
sizeof(GifPixelType));
if (sp->RasterBits == NULL) {
@@ -1135,12 +1153,12 @@
return (GIF_ERROR);
/* Create an extension block with our data */
if (ExtData != NULL) {
- if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,
- &GifFile->ExtensionBlocks,
- ExtFunction, ExtData[0], &ExtData[1])
- == GIF_ERROR)
- return (GIF_ERROR);
- }
+ if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,
+ &GifFile->ExtensionBlocks,
+ ExtFunction, ExtData[0], &ExtData[1])
+ == GIF_ERROR)
+ return (GIF_ERROR);
+ }
while (ExtData != NULL) {
if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR)
return (GIF_ERROR);
@@ -1162,6 +1180,12 @@
}
} while (RecordType != TERMINATE_RECORD_TYPE);
+ /* Sanity check for corrupted file */
+ if (GifFile->ImageCount == 0) {
+ GifFile->Error = D_GIF_ERR_NO_IMAG_DSCR;
+ return(GIF_ERROR);
+ }
+
return (GIF_OK);
}
diff --git a/egif_lib.c b/egif_lib.c
index 4e353ba..3917ec6 100644
--- a/egif_lib.c
+++ b/egif_lib.c
@@ -105,6 +105,7 @@
*Error = E_GIF_ERR_NOT_ENOUGH_MEM;
return NULL;
}
+ /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
if ((Private->HashTable = _InitHashTable()) == NULL) {
free(GifFile);
free(Private);
@@ -123,6 +124,7 @@
Private->FileHandle = FileHandle;
Private->File = f;
Private->FileState = FILE_STATE_WRITE;
+ Private->gif89 = false;
Private->Write = (OutputFunc) 0; /* No user write routine (MRB) */
GifFile->UserData = (void *)NULL; /* No user write handle (MRB) */
@@ -159,6 +161,8 @@
return NULL;
}
+ memset(Private, '\0', sizeof(GifFilePrivateType));
+
Private->HashTable = _InitHashTable();
if (Private->HashTable == NULL) {
free (GifFile);
@@ -186,7 +190,7 @@
/******************************************************************************
Routine to compute the GIF version that will be written on output.
******************************************************************************/
-char *
+const char *
EGifGetGifVersion(GifFileType *GifFile)
{
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
@@ -267,7 +271,7 @@
{
GifByteType Buf[3];
GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
- char *write_version;
+ const char *write_version;
if (Private->FileState & FILE_STATE_SCREEN) {
/* If already has screen descriptor - something is wrong! */
@@ -379,6 +383,10 @@
GifFile->Image.Height = Height;
GifFile->Image.Interlace = Interlace;
if (ColorMap) {
+ if (GifFile->Image.ColorMap != NULL) {
+ GifFreeMapObject(GifFile->Image.ColorMap);
+ GifFile->Image.ColorMap = NULL;
+ }
GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount,
ColorMap->Colors);
if (GifFile->Image.ColorMap == NULL) {
@@ -496,7 +504,7 @@
int
EGifPutComment(GifFileType *GifFile, const char *Comment)
{
- unsigned int length = strlen(Comment);
+ unsigned int length;
char *buf;
length = strlen(Comment);
@@ -750,7 +758,7 @@
This routine should be called last, to close the GIF file.
******************************************************************************/
int
-EGifCloseFile(GifFileType *GifFile)
+EGifCloseFile(GifFileType *GifFile, int *ErrorCode)
{
GifByteType Buf;
GifFilePrivateType *Private;
@@ -764,7 +772,9 @@
return GIF_ERROR;
if (!IS_WRITEABLE(Private)) {
/* This file was NOT open for writing: */
- GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
+ if (ErrorCode != NULL)
+ *ErrorCode = E_GIF_ERR_NOT_WRITEABLE;
+ free(GifFile);
return GIF_ERROR;
}
@@ -785,22 +795,19 @@
if (Private->HashTable) {
free((char *) Private->HashTable);
}
- free((char *) Private);
+ free((char *) Private);
}
if (File && fclose(File) != 0) {
- GifFile->Error = E_GIF_ERR_CLOSE_FAILED;
+ if (ErrorCode != NULL)
+ *ErrorCode = E_GIF_ERR_CLOSE_FAILED;
+ free(GifFile);
return GIF_ERROR;
}
- /*
- * Without the #ifndef, we get spurious warnings because Coverity mistakenly
- * thinks the GIF structure is freed on an error return.
- */
-#ifndef __COVERITY__
free(GifFile);
-#endif /* __COVERITY__ */
-
+ if (ErrorCode != NULL)
+ *ErrorCode = E_GIF_SUCCEEDED;
return GIF_OK;
}
@@ -1140,7 +1147,7 @@
GifFileOut->ExtensionBlockCount) == GIF_ERROR)
return (GIF_ERROR);
- if (EGifCloseFile(GifFileOut) == GIF_ERROR)
+ if (EGifCloseFile(GifFileOut, NULL) == GIF_ERROR)
return (GIF_ERROR);
return (GIF_OK);
diff --git a/gif_err.c b/gif_err.c
index 8de72a0..3ec2a56 100644
--- a/gif_err.c
+++ b/gif_err.c
@@ -12,10 +12,10 @@
/*****************************************************************************
Return a string description of the last GIF error
*****************************************************************************/
-char *
+const char *
GifErrorString(int ErrorCode)
{
- char *Err;
+ const char *Err;
switch (ErrorCode) {
case E_GIF_ERR_OPEN_FAILED:
diff --git a/gif_font.c b/gif_font.c
new file mode 100644
index 0000000..8a02b2d
--- /dev/null
+++ b/gif_font.c
@@ -0,0 +1,259 @@
+/*****************************************************************************
+
+gif_font.c - utility font handling and simple drawing for the GIF library
+
+****************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gif_lib.h"
+
+/*****************************************************************************
+ Ascii 8 by 8 regular font - only first 128 characters are supported.
+*****************************************************************************/
+
+/*
+ * Each array entry holds the bits for 8 horizontal scan lines, topmost
+ * first. The most significant bit of each constant is the leftmost bit of
+ * the scan line.
+ */
+/*@+charint@*/
+const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* Ascii 0 */
+ {0x3c, 0x42, 0xa5, 0x81, 0xbd, 0x42, 0x3c, 0x00}, /* Ascii 1 */
+ {0x3c, 0x7e, 0xdb, 0xff, 0xc3, 0x7e, 0x3c, 0x00}, /* Ascii 2 */
+ {0x00, 0xee, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 3 */
+ {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 4 */
+ {0x00, 0x3c, 0x18, 0xff, 0xff, 0x08, 0x18, 0x00}, /* Ascii 5 */
+ {0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x10, 0x38, 0x00}, /* Ascii 6 */
+ {0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, 0x00, 0x00}, /* Ascii 7 */
+ {0xff, 0xff, 0xe7, 0xc3, 0xe7, 0xff, 0xff, 0xff}, /* Ascii 8 */
+ {0x00, 0x3c, 0x42, 0x81, 0x81, 0x42, 0x3c, 0x00}, /* Ascii 9 */
+ {0xff, 0xc3, 0xbd, 0x7e, 0x7e, 0xbd, 0xc3, 0xff}, /* Ascii 10 */
+ {0x1f, 0x07, 0x0d, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* Ascii 11 */
+ {0x00, 0x7e, 0xc3, 0xc3, 0x7e, 0x18, 0x7e, 0x18}, /* Ascii 12 */
+ {0x04, 0x06, 0x07, 0x04, 0x04, 0xfc, 0xf8, 0x00}, /* Ascii 13 */
+ {0x0c, 0x0a, 0x0d, 0x0b, 0xf9, 0xf9, 0x1f, 0x1f}, /* Ascii 14 */
+ {0x00, 0x92, 0x7c, 0x44, 0xc6, 0x7c, 0x92, 0x00}, /* Ascii 15 */
+ {0x00, 0x00, 0x60, 0x78, 0x7e, 0x78, 0x60, 0x00}, /* Ascii 16 */
+ {0x00, 0x00, 0x06, 0x1e, 0x7e, 0x1e, 0x06, 0x00}, /* Ascii 17 */
+ {0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18}, /* Ascii 18 */
+ {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, /* Ascii 19 */
+ {0xff, 0xb6, 0x76, 0x36, 0x36, 0x36, 0x36, 0x00}, /* Ascii 20 */
+ {0x7e, 0xc1, 0xdc, 0x22, 0x22, 0x1f, 0x83, 0x7e}, /* Ascii 21 */
+ {0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00}, /* Ascii 22 */
+ {0x18, 0x7e, 0x18, 0x18, 0x7e, 0x18, 0x00, 0xff}, /* Ascii 23 */
+ {0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* Ascii 24 */
+ {0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x00}, /* Ascii 25 */
+ {0x00, 0x04, 0x06, 0xff, 0x06, 0x04, 0x00, 0x00}, /* Ascii 26 */
+ {0x00, 0x20, 0x60, 0xff, 0x60, 0x20, 0x00, 0x00}, /* Ascii 27 */
+ {0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xff, 0x00}, /* Ascii 28 */
+ {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00}, /* Ascii 29 */
+ {0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x00, 0x00}, /* Ascii 30 */
+ {0x00, 0x00, 0x00, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 31 */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* */
+ {0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x00}, /* ! */
+ {0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */
+ {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00}, /* # */
+ {0x10, 0x7c, 0xd2, 0x7c, 0x86, 0x7c, 0x10, 0x00}, /* $ */
+ {0xf0, 0x96, 0xfc, 0x18, 0x3e, 0x72, 0xde, 0x00}, /* % */
+ {0x30, 0x48, 0x30, 0x78, 0xce, 0xcc, 0x78, 0x00}, /* & */
+ {0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */
+ {0x10, 0x60, 0xc0, 0xc0, 0xc0, 0x60, 0x10, 0x00}, /* ( */
+ {0x10, 0x0c, 0x06, 0x06, 0x06, 0x0c, 0x10, 0x00}, /* ) */
+ {0x00, 0x54, 0x38, 0xfe, 0x38, 0x54, 0x00, 0x00}, /* * */
+ {0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00}, /* + */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x70}, /* , */
+ {0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00}, /* - */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00}, /* . */
+ {0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00}, /* / */
+ {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* 0 */
+ {0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* 1 */
+ {0x7c, 0xc6, 0x06, 0x0c, 0x30, 0x60, 0xfe, 0x00}, /* 2 */
+ {0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00}, /* 3 */
+ {0x0e, 0x1e, 0x36, 0x66, 0xfe, 0x06, 0x06, 0x00}, /* 4 */
+ {0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xfc, 0x00}, /* 5 */
+ {0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00}, /* 6 */
+ {0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x00}, /* 7 */
+ {0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* 8 */
+ {0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00}, /* 9 */
+ {0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00}, /* : */
+ {0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x20, 0x00}, /* }, */
+ {0x00, 0x1c, 0x30, 0x60, 0x30, 0x1c, 0x00, 0x00}, /* < */
+ {0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00}, /* = */
+ {0x00, 0x70, 0x18, 0x0c, 0x18, 0x70, 0x00, 0x00}, /* > */
+ {0x7c, 0xc6, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00}, /* ? */
+ {0x7c, 0x82, 0x9a, 0xaa, 0xaa, 0x9e, 0x7c, 0x00}, /* @ */
+ {0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00}, /* A */
+ {0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0x00}, /* B */
+ {0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00}, /* C */
+ {0xf8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00}, /* D */
+ {0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xfe, 0x00}, /* E */
+ {0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* F */
+ {0x7c, 0xc6, 0xc0, 0xce, 0xc6, 0xc6, 0x7e, 0x00}, /* G */
+ {0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00}, /* H */
+ {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, /* I */
+ {0x1e, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00}, /* J */
+ {0xc6, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0xc6, 0x00}, /* K */
+ {0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00}, /* L */
+ {0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0x00}, /* M */
+ {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00}, /* N */
+ {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* O */
+ {0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* P */
+ {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x06}, /* Q */
+ {0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0x00}, /* R */
+ {0x78, 0xcc, 0x60, 0x30, 0x18, 0xcc, 0x78, 0x00}, /* S */
+ {0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00}, /* T */
+ {0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* U */
+ {0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* V */
+ {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00}, /* W */
+ {0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00}, /* X */
+ {0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00}, /* Y */
+ {0xfe, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00}, /* Z */
+ {0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00}, /* [ */
+ {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x00}, /* \ */
+ {0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00}, /* ] */
+ {0x00, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00}, /* ^ */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, /* _ */
+ {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */
+ {0x00, 0x00, 0x7c, 0x06, 0x7e, 0xc6, 0x7e, 0x00}, /* a */
+ {0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0x00}, /* b */
+ {0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0x7e, 0x00}, /* c */
+ {0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x00}, /* d */
+ {0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7e, 0x00}, /* e */
+ {0x1e, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x00}, /* f */
+ {0x00, 0x00, 0x7e, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* g */
+ {0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* */
+ {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* i */
+ {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0xf0}, /* j */
+ {0xc0, 0xc0, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0x00}, /* k */
+ {0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* l */
+ {0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xc6, 0xc6, 0x00}, /* m */
+ {0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* n */
+ {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* o */
+ {0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0xc0}, /* p */
+ {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x06}, /* q */
+ {0x00, 0x00, 0x6e, 0x70, 0x60, 0x60, 0x60, 0x00}, /* r */
+ {0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0xfc, 0x00}, /* s */
+ {0x30, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x1c, 0x00}, /* t */
+ {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00}, /* u */
+ {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* v */
+ {0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x00}, /* w */
+ {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00}, /* x */
+ {0x00, 0x00, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* y */
+ {0x00, 0x00, 0xfc, 0x18, 0x30, 0x60, 0xfc, 0x00}, /* z */
+ {0x0e, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0e, 0x00}, /* { */
+ {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, /* | */
+ {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00}, /* } */
+ {0x00, 0x00, 0x70, 0x9a, 0x0e, 0x00, 0x00, 0x00}, /* ~ */
+ {0x00, 0x00, 0x18, 0x3c, 0x66, 0xff, 0x00, 0x00} /* Ascii 127 */
+};
+/*@=charint@*/
+
+void
+GifDrawText8x8(SavedImage *Image,
+ const int x, const int y,
+ const char *legend,
+ const int color)
+{
+ int i, j;
+ int base;
+ const char *cp;
+
+ for (i = 0; i < GIF_FONT_HEIGHT; i++) {
+ base = Image->ImageDesc.Width * (y + i) + x;
+
+ for (cp = legend; *cp; cp++)
+ for (j = 0; j < GIF_FONT_WIDTH; j++) {
+ if (GifAsciiTable8x8[(short)(*cp)][i] & (1 << (GIF_FONT_WIDTH - j)))
+ Image->RasterBits[base] = color;
+ base++;
+ }
+ }
+}
+
+void
+GifDrawBox(SavedImage *Image,
+ const int x, const int y,
+ const int w, const int d,
+ const int color)
+{
+ int j, base = Image->ImageDesc.Width * y + x;
+
+ for (j = 0; j < w; j++)
+ Image->RasterBits[base + j] =
+ Image->RasterBits[base + (d * Image->ImageDesc.Width) + j] = color;
+
+ for (j = 0; j < d; j++)
+ Image->RasterBits[base + j * Image->ImageDesc.Width] =
+ Image->RasterBits[base + j * Image->ImageDesc.Width + w] = color;
+}
+
+void
+GifDrawRectangle(SavedImage *Image,
+ const int x, const int y,
+ const int w, const int d,
+ const int color)
+{
+ unsigned char *bp = Image->RasterBits + Image->ImageDesc.Width * y + x;
+ int i;
+
+ for (i = 0; i < d; i++)
+ memset(bp + (i * Image->ImageDesc.Width), color, (size_t)w);
+}
+
+void
+GifDrawBoxedText8x8(SavedImage *Image,
+ const int x, const int y,
+ const char *legend,
+ const int border,
+ const int bg, const int fg)
+{
+ int j = 0, LineCount = 0, TextWidth = 0;
+ const char *cp;
+ char *dup;
+
+ /* compute size of text to box */
+ for (cp = legend; *cp; cp++)
+ if (*cp == '\r') {
+ if (j > TextWidth)
+ TextWidth = j;
+ j = 0;
+ LineCount++;
+ } else if (*cp != '\t')
+ ++j;
+ LineCount++; /* count last line */
+ if (j > TextWidth) /* last line might be longer than any previous */
+ TextWidth = j;
+
+ /* draw the text */
+ dup = malloc(strlen(legend)+1);
+ /* FIXME: should return bad status, but that would require API change */
+ if (dup != NULL) {
+ int i = 0;
+ /* fill the box */
+ GifDrawRectangle(Image, x + 1, y + 1,
+ border + TextWidth * GIF_FONT_WIDTH + border - 1,
+ border + LineCount * GIF_FONT_HEIGHT + border - 1, bg);
+ (void)strcpy(dup, (char *)legend);
+ cp = strtok((char *)dup, "\r\n");
+ do {
+ int leadspace = 0;
+
+ if (cp[0] == '\t')
+ leadspace = (TextWidth - strlen(++cp)) / 2;
+
+ GifDrawText8x8(Image, x + border + (leadspace * GIF_FONT_WIDTH),
+ y + border + (GIF_FONT_HEIGHT * i++), cp, fg);
+ cp = strtok((char *)NULL, "\r\n");
+ } while (cp);
+ (void)free((void *)dup);
+
+ /* outline the box */
+ GifDrawBox(Image, x, y, border + TextWidth * GIF_FONT_WIDTH + border,
+ border + LineCount * GIF_FONT_HEIGHT + border, fg);
+ }
+}
+
+/* end */
diff --git a/gif_lib.h b/gif_lib.h
index 23df861..078930c 100644
--- a/gif_lib.h
+++ b/gif_lib.h
@@ -12,12 +12,13 @@
#endif /* __cplusplus */
#define GIFLIB_MAJOR 5
-#define GIFLIB_MINOR 0
+#define GIFLIB_MINOR 1
#define GIFLIB_RELEASE 4
#define GIF_ERROR 0
#define GIF_OK 1
+#include <stddef.h>
#include <stdbool.h>
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
@@ -127,9 +128,10 @@
GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
int EGifSpew(GifFileType * GifFile);
-char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
-int EGifCloseFile(GifFileType * GifFile);
+const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
+int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
+#define E_GIF_SUCCEEDED 0
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
#define E_GIF_ERR_WRITE_FAILED 2
#define E_GIF_ERR_HAS_SCRN_DSCR 3
@@ -178,8 +180,9 @@
GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
int DGifSlurp(GifFileType * GifFile);
GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error); /* new one (TVT) */
-int DGifCloseFile(GifFileType * GifFile);
+ int DGifCloseFile(GifFileType * GifFile, int *ErrorCode);
+#define D_GIF_SUCCEEDED 0
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
#define D_GIF_ERR_READ_FAILED 102
#define D_GIF_ERR_NOT_GIF_FILE 103
@@ -222,7 +225,7 @@
/******************************************************************************
Error handling and reporting.
******************************************************************************/
-extern char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
+extern const char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
/*****************************************************************************
Everything below this point is new after version 1.2, supporting `slurp
@@ -241,6 +244,9 @@
GifPixelType ColorTransIn2[]);
extern int GifBitSize(int n);
+extern void *
+reallocarray(void *optr, size_t nmemb, size_t size);
+
/******************************************************************************
Support for the in-core structures allocation (slurp mode).
******************************************************************************/
@@ -273,6 +279,31 @@
GifFileType *GifFile,
int ImageIndex);
+/******************************************************************************
+ The library's internal utility font
+******************************************************************************/
+
+#define GIF_FONT_WIDTH 8
+#define GIF_FONT_HEIGHT 8
+extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
+
+extern void GifDrawText8x8(SavedImage *Image,
+ const int x, const int y,
+ const char *legend, const int color);
+
+extern void GifDrawBox(SavedImage *Image,
+ const int x, const int y,
+ const int w, const int d, const int color);
+
+extern void GifDrawRectangle(SavedImage *Image,
+ const int x, const int y,
+ const int w, const int d, const int color);
+
+extern void GifDrawBoxedText8x8(SavedImage *Image,
+ const int x, const int y,
+ const char *legend,
+ const int border, const int bg, const int fg);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gifalloc.c b/gifalloc.c
index 4cb8cde..3b51868 100644
--- a/gifalloc.c
+++ b/gifalloc.c
@@ -60,6 +60,7 @@
Object->ColorCount = ColorCount;
Object->BitsPerPixel = GifBitSize(ColorCount);
+ Object->SortFlag = false;
if (ColorMap != NULL) {
memcpy((char *)Object->Colors,
@@ -186,9 +187,15 @@
Map[j].Red = Map[j].Green = Map[j].Blue = 0;
/* perhaps we can shrink the map? */
- if (RoundUpTo < ColorUnion->ColorCount)
- ColorUnion->Colors = (GifColorType *)realloc(Map,
- sizeof(GifColorType) * RoundUpTo);
+ if (RoundUpTo < ColorUnion->ColorCount) {
+ GifColorType *new_map = (GifColorType *)reallocarray(Map,
+ RoundUpTo, sizeof(GifColorType));
+ if( new_map == NULL ) {
+ GifFreeMapObject(ColorUnion);
+ return ((ColorMapObject *) NULL);
+ }
+ ColorUnion->Colors = new_map;
+ }
}
ColorUnion->ColorCount = RoundUpTo;
@@ -224,10 +231,14 @@
if (*ExtensionBlocks == NULL)
*ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
- else
- *ExtensionBlocks = (ExtensionBlock *)realloc(*ExtensionBlocks,
- sizeof(ExtensionBlock) *
- (*ExtensionBlockCount + 1));
+ else {
+ ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray
+ (*ExtensionBlocks, (*ExtensionBlockCount + 1),
+ sizeof(ExtensionBlock));
+ if( ep_new == NULL )
+ return (GIF_ERROR);
+ *ExtensionBlocks = ep_new;
+ }
if (*ExtensionBlocks == NULL)
return (GIF_ERROR);
@@ -311,18 +322,16 @@
SavedImage *
GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
{
- SavedImage *sp;
-
if (GifFile->SavedImages == NULL)
GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
else
- GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
- sizeof(SavedImage) * (GifFile->ImageCount + 1));
+ GifFile->SavedImages = (SavedImage *)reallocarray(GifFile->SavedImages,
+ (GifFile->ImageCount + 1), sizeof(SavedImage));
if (GifFile->SavedImages == NULL)
return ((SavedImage *)NULL);
else {
- sp = &GifFile->SavedImages[GifFile->ImageCount++];
+ SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
memset((char *)sp, '\0', sizeof(SavedImage));
if (CopyFrom != NULL) {
@@ -346,9 +355,10 @@
}
/* next, the raster */
- sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
- CopyFrom->ImageDesc.Height *
- CopyFrom->ImageDesc.Width);
+ sp->RasterBits = (unsigned char *)reallocarray(NULL,
+ (CopyFrom->ImageDesc.Height *
+ CopyFrom->ImageDesc.Width),
+ sizeof(GifPixelType));
if (sp->RasterBits == NULL) {
FreeLastSavedImage(GifFile);
return (SavedImage *)(NULL);
@@ -359,9 +369,9 @@
/* finally, the extension blocks */
if (sp->ExtensionBlocks != NULL) {
- sp->ExtensionBlocks = (ExtensionBlock *)malloc(
- sizeof(ExtensionBlock) *
- CopyFrom->ExtensionBlockCount);
+ sp->ExtensionBlocks = (ExtensionBlock *)reallocarray(NULL,
+ CopyFrom->ExtensionBlockCount,
+ sizeof(ExtensionBlock));
if (sp->ExtensionBlocks == NULL) {
FreeLastSavedImage(GifFile);
return (SavedImage *)(NULL);
diff --git a/openbsd-reallocarray.c b/openbsd-reallocarray.c
new file mode 100644
index 0000000..41a3326
--- /dev/null
+++ b/openbsd-reallocarray.c
@@ -0,0 +1,39 @@
+/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(optr, size * nmemb);
+}
diff --git a/quantize.c b/quantize.c
index fc31f36..e5d4a59 100644
--- a/quantize.c
+++ b/quantize.c
@@ -234,6 +234,17 @@
j++, QuantizedColor = QuantizedColor->Pnext)
SortArray[j] = QuantizedColor;
+ /*
+ * Because qsort isn't stable, this can produce differing
+ * results for the order of tuples depending on platform
+ * details of how qsort() is implemented.
+ *
+ * We mitigate this problem by sorting on all three axes rather
+ * than only the one specied by SortRGBAxis; that way the instability
+ * can only become an issue if there are multiple color indices
+ * referring to identical RGB tuples. Older versions of this
+ * sorted on only the one axis.
+ */
qsort(SortArray, NewColorSubdiv[Index].NumEntries,
sizeof(QuantizedColorType *), SortCmpRtn);
@@ -298,12 +309,22 @@
/****************************************************************************
Routine called by qsort to compare two entries.
*****************************************************************************/
+
static int
SortCmpRtn(const void *Entry1,
const void *Entry2) {
+ QuantizedColorType *entry1 = (*((QuantizedColorType **) Entry1));
+ QuantizedColorType *entry2 = (*((QuantizedColorType **) Entry2));
- return (*((QuantizedColorType **) Entry1))->RGB[SortRGBAxis] -
- (*((QuantizedColorType **) Entry2))->RGB[SortRGBAxis];
+ /* sort on all axes of the color space! */
+ int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256
+ + entry1->RGB[(SortRGBAxis+1) % 3] * 256
+ + entry1->RGB[(SortRGBAxis+2) % 3];
+ int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256
+ + entry2->RGB[(SortRGBAxis+1) % 3] * 256
+ + entry2->RGB[(SortRGBAxis+2) % 3];
+
+ return hash1 - hash2;
}
/* end */