gdtest.c (libgd-2.3.2) | : | gdtest.c (libgd-2.3.3) | ||
---|---|---|---|---|
#ifdef HAVE_CONFIG_H | #ifdef HAVE_CONFIG_H | |||
#include <config.h> | #include <config.h> | |||
#endif | #endif | |||
#include <assert.h> | #include <assert.h> | |||
#include <setjmp.h> | #include <setjmp.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <string.h> | #include <string.h> | |||
#include <math.h> | #include <math.h> | |||
#include <limits.h> | #include <limits.h> | |||
#include <time.h> | ||||
#ifdef HAVE_DIRENT_H | #ifdef HAVE_DIRENT_H | |||
#include <dirent.h> | #include <dirent.h> | |||
#endif | #endif | |||
#ifdef HAVE_UNISTD_H | #ifdef HAVE_UNISTD_H | |||
#include <unistd.h> | #include <unistd.h> | |||
#endif | #endif | |||
#ifdef HAVE_SYS_STAT_H | #ifdef HAVE_SYS_STAT_H | |||
#include <sys/stat.h> | #include <sys/stat.h> | |||
#endif | #endif | |||
#ifdef HAVE_SYS_TYPES_H | #ifdef HAVE_SYS_TYPES_H | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#endif | #endif | |||
#ifdef _WIN32 | #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) | |||
#include "readdir.h" | #include "readdir.h" | |||
#include <errno.h> | #include <errno.h> | |||
#endif | #endif | |||
#if defined(__MINGW32__) || defined(__MINGW64__) | ||||
# define lstat stat | ||||
#endif | ||||
#include "gd_intern.h" | ||||
/* GDTEST_TOP_DIR is defined in other compile ways except msys | /* GDTEST_TOP_DIR is defined in other compile ways except msys | |||
* test_config.h is created by windows/msys/run_test.sh*/ | * test_config.h is created by windows/msys/run_test.sh*/ | |||
#ifndef GDTEST_TOP_DIR | #ifndef GDTEST_TOP_DIR | |||
#include <test_config.h> | #include <test_config.h> | |||
#endif | #endif | |||
#include "gd.h" | #include "gd.h" | |||
#include "gdtest.h" | #include "gdtest.h" | |||
skipping to change at line 78 | skipping to change at line 83 | |||
if (fp == NULL) { | if (fp == NULL) { | |||
return NULL; | return NULL; | |||
} | } | |||
image = gdImageCreateFromPng(fp); | image = gdImageCreateFromPng(fp); | |||
fclose(fp); | fclose(fp); | |||
return image; | return image; | |||
} | } | |||
static char *tmpdir_base; | static char *tmpdir_base; | |||
int gdTestIsDir(char *path) { | ||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) | ||||
WIN32_FILE_ATTRIBUTE_DATA data; | ||||
if (!GetFileAttributesEx(path, GetFileExInfoStandard, &data)) { | ||||
return 0; | ||||
} | ||||
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | ||||
return 0; | ||||
} else { | ||||
return 1; | ||||
} | ||||
#else | ||||
struct stat st; | ||||
if (lstat(path, &st) != 0) | ||||
if (S_ISDIR(st.st_mode)) | ||||
return 1; | ||||
return 0; | ||||
#endif | ||||
} | ||||
/* This is kind of hacky, but it's meant to be simple. */ | /* This is kind of hacky, but it's meant to be simple. */ | |||
static void _clean_dir(const char *dir) | static void _clean_dir(const char *dir) | |||
{ | { | |||
DIR *d; | DIR *d; | |||
struct dirent *de; | struct dirent *de; | |||
d = opendir(dir); | d = opendir(dir); | |||
if (d == NULL) | if (d == NULL) | |||
return; | return; | |||
if (chdir(dir) != 0) | if (chdir(dir) != 0) | |||
goto done; | goto done; | |||
while ((de = readdir(d)) != NULL) { | while ((de = readdir(d)) != NULL) { | |||
struct stat st; | struct stat st; | |||
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0 ) | if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0 ) | |||
continue; | continue; | |||
#ifdef _WIN32 | #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) | |||
{ | { | |||
WIN32_FILE_ATTRIBUTE_DATA data; | WIN32_FILE_ATTRIBUTE_DATA data; | |||
if (!GetFileAttributesEx(de->d_name, GetFileExInfoStandard, &data )) { | if (!GetFileAttributesEx(de->d_name, GetFileExInfoStandard, &data )) { | |||
continue; | continue; | |||
} | } | |||
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | |||
_clean_dir(de->d_name); | _clean_dir(de->d_name); | |||
} else { | } else { | |||
unlink(de->d_name); | unlink(de->d_name); | |||
skipping to change at line 136 | skipping to change at line 161 | |||
closedir(d); | closedir(d); | |||
rmdir(dir); | rmdir(dir); | |||
} | } | |||
static void tmpdir_cleanup(void) | static void tmpdir_cleanup(void) | |||
{ | { | |||
_clean_dir(tmpdir_base); | _clean_dir(tmpdir_base); | |||
free(tmpdir_base); | free(tmpdir_base); | |||
} | } | |||
#ifdef _WIN32 | #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) | |||
char* strrstr (char* haystack, char* needle) | ||||
{ | ||||
int needle_length = strlen(needle); | ||||
char * haystack_end = haystack + strlen(haystack) - needle_length; | ||||
char * p; | ||||
int i; | ||||
for(p = haystack_end; p >= haystack; --p) | ||||
{ | ||||
for(i = 0; i < needle_length; ++i) { | ||||
if(p[i] != needle[i]) | ||||
goto next; | ||||
} | ||||
return p; | ||||
next:; | ||||
} | ||||
return 0; | ||||
} | ||||
typedef VOID (WINAPI *MyGetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTi me); | typedef VOID (WINAPI *MyGetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTi me); | |||
static MyGetSystemTimeAsFileTime get_time_func(void) | static MyGetSystemTimeAsFileTime get_time_func(void) | |||
{ | { | |||
MyGetSystemTimeAsFileTime timefunc = NULL; | MyGetSystemTimeAsFileTime timefunc = NULL; | |||
HMODULE hMod = GetModuleHandle("kernel32.dll"); | HMODULE hMod = GetModuleHandle("kernel32.dll"); | |||
if (hMod) { | if (hMod) { | |||
/* Max possible resolution <1us, win8/server2012 */ | /* Max possible resolution <1us, win8/server2012 */ | |||
skipping to change at line 205 | skipping to change at line 211 | |||
ff = fft.QuadPart; | ff = fft.QuadPart; | |||
ff /= 10ULL; /* convert to microseconds */ | ff /= 10ULL; /* convert to microseconds */ | |||
ff -= 11644473600000000ULL; /* convert to unix epoch */ | ff -= 11644473600000000ULL; /* convert to unix epoch */ | |||
tv->tv_sec = (long)(ff / 1000000ULL); | tv->tv_sec = (long)(ff / 1000000ULL); | |||
tv->tv_usec = (long)(ff % 1000000ULL); | tv->tv_usec = (long)(ff % 1000000ULL); | |||
return 0; | return 0; | |||
} | } | |||
#endif | ||||
#if defined(_WIN32) | ||||
static void randtemplate(char *template, size_t l) { | ||||
// just to avoid calls within the same second | ||||
srand(time (NULL) + (unsigned int)template); | ||||
for (size_t i = l - 6; i < l; i++) { | ||||
int r = rand(); | ||||
if ((r / (RAND_MAX + 1)) > ((RAND_MAX + 1) / 2)) | ||||
template[i] = 'A' + (double) rand () / (RAND_MAX + 1) * ( | ||||
'Z' - 'A'); | ||||
else | ||||
template[i] = 'a' + (double) rand () / (RAND_MAX + 1) * ( | ||||
'z' - 'a'); | ||||
} | ||||
} | ||||
char* strrstr (char* haystack, char* needle) | ||||
{ | ||||
int needle_length = strlen(needle); | ||||
char * haystack_end = haystack + strlen(haystack) - needle_length; | ||||
char * p; | ||||
int i; | ||||
for(p = haystack_end; p >= haystack; --p) | ||||
{ | ||||
for(i = 0; i < needle_length; ++i) { | ||||
if(p[i] != needle[i]) | ||||
goto next; | ||||
} | ||||
return p; | ||||
next:; | ||||
} | ||||
return 0; | ||||
} | ||||
static char * | static char * | |||
mkdtemp (char *tmpl) | mkdtemp (char *tmpl) | |||
{ | { | |||
static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | size_t l; | |||
static const int NLETTERS = sizeof (letters) - 1; | char attempts = 8; | |||
static int counter = 0; | int res = 0; | |||
char *XXXXXX; | ||||
struct timeval tv; | ||||
__int64 value; | ||||
int count; | ||||
/* find the last occurrence of "XXXXXX" */ | if (tmpl == NULL) { | |||
XXXXXX = strrstr(tmpl, "XXXXXX"); | errno = EINVAL; | |||
return NULL; | ||||
} | ||||
if (!XXXXXX || strncmp (XXXXXX, "XXXXXX", 6)) { | l = strlen (tmpl); | |||
if (l < 6 || strcmp (&tmpl[l - 6], "XXXXXX") != 0) { | ||||
errno = EINVAL; | errno = EINVAL; | |||
return NULL; | return NULL; | |||
} | } | |||
do { | ||||
randtemplate (tmpl, l); | ||||
res = mkdir(tmpl); | ||||
attempts--; | ||||
} while (attempts > 0 && res != 0 ); | ||||
/* Get some more or less random data. */ | if (res == 0) { | |||
getfilesystemtime(&tv); | return tmpl; | |||
value = (tv.tv_usec ^ tv.tv_sec) + counter++; | } | |||
if (errno != EEXIST) { | ||||
for (count = 0; count < 100; value += 7777, ++count) { | printf("Failed to create tmp dir, last attempt %s.", tmpl); | |||
__int64 v = value; | return NULL; | |||
/* Fill in the random bits. */ | ||||
XXXXXX[0] = letters[v % NLETTERS]; | ||||
v /= NLETTERS; | ||||
XXXXXX[1] = letters[v % NLETTERS]; | ||||
v /= NLETTERS; | ||||
XXXXXX[2] = letters[v % NLETTERS]; | ||||
v /= NLETTERS; | ||||
XXXXXX[3] = letters[v % NLETTERS]; | ||||
v /= NLETTERS; | ||||
XXXXXX[4] = letters[v % NLETTERS]; | ||||
v /= NLETTERS; | ||||
XXXXXX[5] = letters[v % NLETTERS]; | ||||
/* tmpl is in UTF-8 on Windows, thus use g_mkdir() */ | ||||
if (mkdir(tmpl) == 0) { | ||||
return tmpl; | ||||
} | ||||
printf("failed to create directory\n"); | ||||
if (errno != EEXIST) | ||||
/* Any other error will apply also to other names we migh | ||||
t | ||||
* try, and there are 2^32 or so of them, so give up now | ||||
. | ||||
*/ | ||||
return NULL; | ||||
} | } | |||
/* We got out of the loop because we ran out of combinations to try. */ | /* We got out of the loop because we ran out of combinations to try. */ | |||
errno = EEXIST; | errno = EEXIST; | |||
return NULL; | return NULL; | |||
} | } | |||
#endif | #endif | |||
const char *gdTestTempDir(void) | const char *gdTestTempDir(void) | |||
{ | { | |||
if (tmpdir_base == NULL) { | if (tmpdir_base == NULL) { | |||
char *tmpdir; | char *tmpdir; | |||
#ifdef _WIN32 | #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) | |||
char tmpdir_root[MAX_PATH]; | char tmpdir_root[MAXPATHLEN]; | |||
size_t tmpdir_root_len = GetTempPath(MAX_PATH, tmpdir_root); | size_t tmpdir_root_len = GetTempPath(MAX_PATH, tmpdir_root); | |||
gdTestAssert(!(tmpdir_root_len > MAX_PATH || (tmpdir_root_len == | if ((tmpdir_root_len + 30 > MAX_PATH) || (tmpdir_root_len == 0)) | |||
0))); | { | |||
gdTestAssert((tmpdir_root_len + 30 < MAX_PATH)); | printf("Tmp dir path too long or 0 length <%s>\n", tmpdir | |||
_root); | ||||
return NULL; | ||||
} | ||||
#else | #else | |||
char *tmpdir_root; | char *tmpdir_root; | |||
tmpdir_root = getenv("TMPDIR"); | tmpdir_root = getenv("TMPDIR"); | |||
if (tmpdir_root == NULL) | if (tmpdir_root == NULL) { | |||
tmpdir_root = "/tmp"; | // Mingw defines it | |||
tmpdir_root = getenv("TMP"); | ||||
if (tmpdir_root == NULL) { | ||||
// Fall back here. | ||||
tmpdir_root = "/tmp"; | ||||
if (!gdTestIsDir(tmpdir_root)) { | ||||
printf("tmpdir failed to be used or initi | ||||
alized (%s).", tmpdir_root); | ||||
exit(2); | ||||
} | ||||
} | ||||
} | ||||
#endif | #endif | |||
/* The constant here is a lazy over-estimate. */ | /* The constant here is a lazy over-estimate. */ | |||
tmpdir = malloc(strlen(tmpdir_root) + 30); | tmpdir = malloc(strlen(tmpdir_root) + 30); | |||
gdTestAssert(tmpdir != NULL); | if (tmpdir == NULL) { | |||
#ifdef _WIN32 | printf("cannot alloc tmpdir path."); | |||
return NULL; | ||||
} | ||||
#if defined(_WIN32) | ||||
sprintf(tmpdir, "%sgdtest.XXXXXX", tmpdir_root); | sprintf(tmpdir, "%sgdtest.XXXXXX", tmpdir_root); | |||
#else | #else | |||
sprintf(tmpdir, "%s/gdtest.XXXXXX", tmpdir_root); | sprintf(tmpdir, "%s/gdtest.XXXXXX", tmpdir_root); | |||
#endif | #endif | |||
tmpdir_base = mkdtemp(tmpdir); | tmpdir_base = mkdtemp(tmpdir); | |||
gdTestAssert(tmpdir_base != NULL); | if (tmpdir_base == NULL) { | |||
printf("failed to generate the tmp dir path (%s).", tmpdi | ||||
r); | ||||
return NULL; | ||||
} | ||||
atexit(tmpdir_cleanup); | atexit(tmpdir_cleanup); | |||
} | } | |||
return tmpdir_base; | return tmpdir_base; | |||
} | } | |||
char *gdTestTempFile(const char *template) | char *gdTestTempFile(const char *template) | |||
{ | { | |||
const char *tempdir = gdTestTempDir(); | const char *tempdir = gdTestTempDir(); | |||
char *ret; | char *ret; | |||
if (tempdir == NULL) { | ||||
#ifdef _WIN32 | return NULL; | |||
} | ||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) | ||||
{ | { | |||
char *tmpfilename; | char *tmpfilename; | |||
UINT error; | UINT error; | |||
ret = malloc(MAX_PATH); | ret = malloc(MAX_PATH); | |||
gdTestAssert(ret != NULL); | if (ret == NULL) { | |||
printf("Failed to alloc tmp path"); | ||||
return NULL; | ||||
} | ||||
if (template == NULL) { | if (template == NULL) { | |||
error = GetTempFileName(tempdir, | error = GetTempFileName(tempdir, | |||
"gdtest", | "gdtest", | |||
0, | 0, | |||
ret); | ret); | |||
gdTestAssert(error != 0); | if (error = 0) { | |||
printf("GetTempFileName failed."); | ||||
gdFree(ret); | ||||
return NULL; | ||||
} | ||||
} else { | } else { | |||
sprintf(ret, "%s\\%s", tempdir, template); | sprintf(ret, "%s\\%s", tempdir, template); | |||
} | } | |||
} | } | |||
#else | #else | |||
if (template == NULL) { | if (template == NULL) { | |||
template = "gdtemp.XXXXXX"; | template = "gdtemp.XXXXXX"; | |||
} | } | |||
ret = malloc(strlen(tempdir) + 10 + strlen(template)); | ret = malloc(strlen(tempdir) + 10 + strlen(template)); | |||
gdTestAssert(ret != NULL); | if (ret == NULL) { | |||
printf("Failed to alloc tmp path"); | ||||
return NULL; | ||||
} | ||||
sprintf(ret, "%s/%s", tempdir, template); | sprintf(ret, "%s/%s", tempdir, template); | |||
if (strstr(template, "XXXXXX") != NULL) { | if (strstr(template, "XXXXXX") != NULL) { | |||
int fd = mkstemp(ret); | int fd = mkstemp(ret); | |||
gdTestAssert(fd != -1); | if (fd == -1) { | |||
printf("mkstemp failed"); | ||||
gdFree(ret); | ||||
return NULL; | ||||
} | ||||
close(fd); | close(fd); | |||
} | } | |||
#endif | #endif | |||
return ret; | return ret; | |||
} | } | |||
FILE *gdTestTempFp(void) | FILE *gdTestTempFp(void) | |||
{ | { | |||
char *file = gdTestTempFile(NULL); | char *file = gdTestTempFile(NULL); | |||
FILE *fp = fopen(file, "wb"); | FILE *fp = fopen(file, "wb"); | |||
gdTestAssert(fp != NULL); | if (fp == NULL) { | |||
printf("fail to open tmp file"); | ||||
return NULL; | ||||
} | ||||
free(file); | free(file); | |||
return fp; | return fp; | |||
} | } | |||
char *gdTestFilePathV(const char *path, va_list args) | char *gdTestFilePathV(const char *path, va_list args) | |||
{ | { | |||
size_t len; | size_t len; | |||
const char *p; | const char *p; | |||
char *file; | char *file; | |||
va_list args_len; | va_list args_len; | |||
skipping to change at line 362 | skipping to change at line 421 | |||
va_copy(args_len, args); | va_copy(args_len, args); | |||
len = strlen(GDTEST_TOP_DIR) + 1; | len = strlen(GDTEST_TOP_DIR) + 1; | |||
p = path; | p = path; | |||
do { | do { | |||
len += strlen(p) + 1; | len += strlen(p) + 1; | |||
} while ((p = va_arg(args_len, const char *)) != NULL); | } while ((p = va_arg(args_len, const char *)) != NULL); | |||
va_end(args_len); | va_end(args_len); | |||
/* Now build the path. */ | /* Now build the path. */ | |||
file = malloc(len); | file = malloc(len); | |||
gdTestAssert(file != NULL); | if (file == NULL) { | |||
printf("failed to alloc path."); | ||||
return NULL; | ||||
} | ||||
strcpy(file, GDTEST_TOP_DIR); | strcpy(file, GDTEST_TOP_DIR); | |||
p = path; | p = path; | |||
do { | do { | |||
#ifdef _WIN32 | #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) | |||
strcat(file, "\\"); | strcat(file, "\\"); | |||
#else | #else | |||
strcat(file, "/"); | strcat(file, "/"); | |||
#endif | #endif | |||
strcat(file, p); | strcat(file, p); | |||
} while ((p = va_arg(args, const char *)) != NULL); | } while ((p = va_arg(args, const char *)) != NULL); | |||
va_end(args); | va_end(args); | |||
return file; | return file; | |||
skipping to change at line 395 | skipping to change at line 457 | |||
FILE *gdTestFileOpenX(const char *path, ...) | FILE *gdTestFileOpenX(const char *path, ...) | |||
{ | { | |||
va_list args; | va_list args; | |||
FILE *fp; | FILE *fp; | |||
char *file; | char *file; | |||
va_start(args, path); | va_start(args, path); | |||
file = gdTestFilePathV(path, args); | file = gdTestFilePathV(path, args); | |||
fp = fopen(file, "rb"); | fp = fopen(file, "rb"); | |||
gdTestAssert(fp != NULL); | if (fp == NULL) { | |||
printf("failed to open path (rb)."); | ||||
return NULL; | ||||
} | ||||
free(file); | free(file); | |||
return fp; | return fp; | |||
} | } | |||
/* Compare two buffers, returning the number of pixels that are | /* Compare two buffers, returning the number of pixels that are | |||
* different and the maximum difference of any single color channel in | * different and the maximum difference of any single color channel in | |||
* result_ret. | * result_ret. | |||
* | * | |||
* This function should be rewritten to compare all formats supported by | * This function should be rewritten to compare all formats supported by | |||
* cairo_format_t instead of taking a mask as a parameter. | * cairo_format_t instead of taking a mask as a parameter. | |||
End of changes. 28 change blocks. | ||||
84 lines changed or deleted | 152 lines changed or added |