2003-11-14 16:48:48 +00:00
|
|
|
/*
|
2024-10-29 16:10:51 -04:00
|
|
|
* Copyright © 2024 Thomas E. Dickey
|
2004-12-04 00:42:47 +00:00
|
|
|
* Copyright © 2002 Keith Packard
|
2003-11-14 16:48:48 +00:00
|
|
|
*
|
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
|
* the above copyright notice appear in all copies and that both that
|
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
|
* documentation, and that the name of Keith Packard not be used in
|
|
|
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
|
|
|
* specific, written prior permission. Keith Packard makes no
|
|
|
|
|
* representations about the suitability of this software for any purpose. It
|
|
|
|
|
* is provided "as is" without express or implied warranty.
|
|
|
|
|
*
|
|
|
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
|
|
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, 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 "xcursorint.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
#ifdef DEBUG_XCURSOR
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
void _XcursorTrace(const char *fmt, ...)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
2024-10-30 19:16:09 -04:00
|
|
|
FILE *fp = fopen("/tmp/xcursor.log", "a");
|
|
|
|
|
if (fp != NULL) {
|
|
|
|
|
unsigned save = umask(0);
|
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
vfprintf(fp, fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
umask(save);
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-11-14 16:48:48 +00:00
|
|
|
|
2024-10-31 18:59:24 -04:00
|
|
|
void *_XcursorReturnAddr(void *addr)
|
2024-10-30 19:16:09 -04:00
|
|
|
{
|
2024-10-31 18:59:24 -04:00
|
|
|
_XcursorTrace(T_RETURN(p), addr);
|
|
|
|
|
return addr;
|
2024-10-30 19:16:09 -04:00
|
|
|
}
|
2017-10-21 23:47:52 +02:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
int _XcursorReturnCode(int code)
|
|
|
|
|
{
|
|
|
|
|
_XcursorTrace(T_RETURN(d), code);
|
|
|
|
|
return code;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 18:59:24 -04:00
|
|
|
unsigned long _XcursorReturnLong(unsigned long code)
|
2024-10-30 19:16:09 -04:00
|
|
|
{
|
2024-10-31 18:59:24 -04:00
|
|
|
_XcursorTrace(T_RETURN(lu), code);
|
|
|
|
|
return code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned _XcursorReturnUint(unsigned code)
|
|
|
|
|
{
|
|
|
|
|
_XcursorTrace(T_RETURN(u), code);
|
|
|
|
|
return code;
|
2024-10-30 19:16:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _XcursorReturnVoid(void)
|
|
|
|
|
{
|
|
|
|
|
_XcursorTrace(T_RETURN(s), "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_XCURSOR */
|
|
|
|
|
|
|
|
|
|
XcursorImage *
|
|
|
|
|
XcursorImageCreate (int width, int height)
|
|
|
|
|
{
|
|
|
|
|
XcursorImage *image = NULL;
|
|
|
|
|
|
|
|
|
|
enterFunc((T_CALLED(XcursorImageCreate) "(%d, %d)\n", width, height));
|
|
|
|
|
|
|
|
|
|
if (width < 0 || height < 0) {
|
|
|
|
|
/* EMPTY */;
|
|
|
|
|
} else if (width > XCURSOR_IMAGE_MAX_SIZE
|
|
|
|
|
|| height > XCURSOR_IMAGE_MAX_SIZE) {
|
|
|
|
|
/* EMPTY */;
|
|
|
|
|
} else {
|
|
|
|
|
image = malloc (sizeof (XcursorImage) +
|
|
|
|
|
(size_t) (width * height) * sizeof (XcursorPixel));
|
|
|
|
|
if (image) {
|
|
|
|
|
image->version = XCURSOR_IMAGE_VERSION;
|
|
|
|
|
image->pixels = (XcursorPixel *) (image + 1);
|
|
|
|
|
image->size = (XcursorDim) (width > height ? width : height);
|
|
|
|
|
image->width = (XcursorDim) width;
|
|
|
|
|
image->height = (XcursorDim) height;
|
|
|
|
|
image->delay = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
returnAddr(image);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
XcursorImageDestroy (XcursorImage *image)
|
|
|
|
|
{
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorImageDestroy ) "(%p)\n", (void*)image));
|
|
|
|
|
|
2006-08-12 19:55:44 +03:00
|
|
|
free (image);
|
2024-10-30 19:16:09 -04:00
|
|
|
|
|
|
|
|
returnVoid();
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorImages *
|
|
|
|
|
XcursorImagesCreate (int size)
|
|
|
|
|
{
|
|
|
|
|
XcursorImages *images;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorImagesCreate) "(%d)\n", size));
|
|
|
|
|
|
2011-09-16 21:26:17 -07:00
|
|
|
images = malloc (sizeof (XcursorImages) +
|
2021-03-10 19:36:04 -05:00
|
|
|
(size_t) size * sizeof (XcursorImage *));
|
2024-10-30 19:16:09 -04:00
|
|
|
if (images) {
|
|
|
|
|
images->nimage = 0;
|
|
|
|
|
images->images = (XcursorImage **) (images + 1);
|
|
|
|
|
images->name = NULL;
|
|
|
|
|
}
|
|
|
|
|
returnAddr(images);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
XcursorImagesDestroy (XcursorImages *images)
|
|
|
|
|
{
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorImagesDestroy) "(%p)\n", (void*)images));
|
2003-11-14 16:48:48 +00:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
if (images) {
|
|
|
|
|
int n;
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
for (n = 0; n < images->nimage; n++)
|
|
|
|
|
XcursorImageDestroy (images->images[n]);
|
|
|
|
|
if (images->name)
|
|
|
|
|
free (images->name);
|
|
|
|
|
free (images);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
returnVoid();
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
2004-04-23 18:43:40 +00:00
|
|
|
void
|
|
|
|
|
XcursorImagesSetName (XcursorImages *images, const char *name)
|
|
|
|
|
{
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorImagesSetName) "(%p, \"%s\")\n",
|
|
|
|
|
(void*)images,
|
|
|
|
|
NonNull(name)));
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
if (images && name) {
|
|
|
|
|
char *new = strdup (name);
|
2004-04-23 18:43:40 +00:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
if (new) {
|
|
|
|
|
if (images->name)
|
|
|
|
|
free (images->name);
|
|
|
|
|
images->name = new;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
returnVoid();
|
2004-04-23 18:43:40 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorComment *
|
|
|
|
|
XcursorCommentCreate (XcursorUInt comment_type, int length)
|
|
|
|
|
{
|
|
|
|
|
XcursorComment *comment;
|
|
|
|
|
|
2017-10-21 23:47:52 +02:00
|
|
|
if (length < 0 || length > XCURSOR_COMMENT_MAX_LEN)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
|
2021-03-10 19:36:04 -05:00
|
|
|
comment = malloc (sizeof (XcursorComment) + (size_t) length + 1);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!comment)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
comment->version = XCURSOR_COMMENT_VERSION;
|
|
|
|
|
comment->comment_type = comment_type;
|
|
|
|
|
comment->comment = (char *) (comment + 1);
|
|
|
|
|
comment->comment[0] = '\0';
|
|
|
|
|
return comment;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
XcursorCommentDestroy (XcursorComment *comment)
|
|
|
|
|
{
|
2006-08-12 19:55:44 +03:00
|
|
|
free (comment);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorComments *
|
|
|
|
|
XcursorCommentsCreate (int size)
|
|
|
|
|
{
|
|
|
|
|
XcursorComments *comments;
|
|
|
|
|
|
|
|
|
|
comments = malloc (sizeof (XcursorComments) +
|
2021-03-10 19:36:04 -05:00
|
|
|
(size_t) size * sizeof (XcursorComment *));
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!comments)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
comments->ncomment = 0;
|
|
|
|
|
comments->comments = (XcursorComment **) (comments + 1);
|
|
|
|
|
return comments;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
XcursorCommentsDestroy (XcursorComments *comments)
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!comments)
|
2024-11-03 17:36:03 -05:00
|
|
|
return;
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
for (n = 0; n < comments->ncomment; n++)
|
|
|
|
|
XcursorCommentDestroy (comments->comments[n]);
|
|
|
|
|
free (comments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
|
|
|
|
_XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
|
|
|
|
|
{
|
|
|
|
|
unsigned char bytes[4];
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !u)
|
2024-11-03 17:36:03 -05:00
|
|
|
return XcursorFalse;
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
if ((*file->read) (file, bytes, 4) != 4)
|
2024-11-03 17:36:03 -05:00
|
|
|
return XcursorFalse;
|
2020-08-30 15:37:19 +02:00
|
|
|
|
|
|
|
|
*u = ((XcursorUInt)(bytes[0]) << 0) |
|
2024-11-03 17:36:03 -05:00
|
|
|
((XcursorUInt)(bytes[1]) << 8) |
|
2020-08-30 15:37:19 +02:00
|
|
|
((XcursorUInt)(bytes[2]) << 16) |
|
|
|
|
|
((XcursorUInt)(bytes[3]) << 24);
|
2003-11-14 16:48:48 +00:00
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
|
|
|
|
_XcursorReadBytes (XcursorFile *file, char *bytes, int length)
|
|
|
|
|
{
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !bytes || (*file->read) (file, (unsigned char *) bytes, length) != length)
|
2003-11-14 16:48:48 +00:00
|
|
|
return XcursorFalse;
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
|
|
|
|
_XcursorWriteUInt (XcursorFile *file, XcursorUInt u)
|
|
|
|
|
{
|
|
|
|
|
unsigned char bytes[4];
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
|
|
|
|
return XcursorFalse;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2021-03-10 19:36:04 -05:00
|
|
|
bytes[0] = (unsigned char)(u);
|
|
|
|
|
bytes[1] = (unsigned char)(u >> 8);
|
|
|
|
|
bytes[2] = (unsigned char)(u >> 16);
|
|
|
|
|
bytes[3] = (unsigned char)(u >> 24);
|
2003-11-14 16:48:48 +00:00
|
|
|
if ((*file->write) (file, bytes, 4) != 4)
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
|
|
|
|
_XcursorWriteBytes (XcursorFile *file, char *bytes, int length)
|
|
|
|
|
{
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !bytes || (*file->write) (file, (unsigned char *) bytes, length) != length)
|
2003-11-14 16:48:48 +00:00
|
|
|
return XcursorFalse;
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader)
|
|
|
|
|
{
|
2006-08-12 19:55:44 +03:00
|
|
|
free (fileHeader);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorFileHeader *
|
2013-04-12 21:17:28 -07:00
|
|
|
_XcursorFileHeaderCreate (XcursorUInt ntoc)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
XcursorFileHeader *fileHeader;
|
|
|
|
|
|
|
|
|
|
if (ntoc > 0x10000)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader = malloc (sizeof (XcursorFileHeader) +
|
|
|
|
|
ntoc * sizeof (XcursorFileToc));
|
|
|
|
|
if (!fileHeader)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader->magic = XCURSOR_MAGIC;
|
|
|
|
|
fileHeader->header = XCURSOR_FILE_HEADER_LEN;
|
2004-04-23 18:43:40 +00:00
|
|
|
fileHeader->version = XCURSOR_FILE_VERSION;
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader->ntoc = ntoc;
|
|
|
|
|
fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1);
|
|
|
|
|
return fileHeader;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorFileHeader *
|
|
|
|
|
_XcursorReadFileHeader (XcursorFile *file)
|
|
|
|
|
{
|
|
|
|
|
XcursorFileHeader head, *fileHeader;
|
|
|
|
|
XcursorUInt skip;
|
2021-03-11 17:18:31 -05:00
|
|
|
XcursorUInt n;
|
2005-06-29 18:46:53 +00:00
|
|
|
|
|
|
|
|
if (!file)
|
|
|
|
|
return NULL;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.magic))
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
if (head.magic != XCURSOR_MAGIC)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.header))
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2024-09-12 22:23:50 +02:00
|
|
|
if (head.header < XCURSOR_FILE_HEADER_LEN)
|
|
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.version))
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.ntoc))
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
skip = head.header - XCURSOR_FILE_HEADER_LEN;
|
|
|
|
|
if (skip)
|
|
|
|
|
if ((*file->seek) (file, skip, SEEK_CUR) == EOF)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader = _XcursorFileHeaderCreate (head.ntoc);
|
|
|
|
|
if (!fileHeader)
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader->magic = head.magic;
|
|
|
|
|
fileHeader->header = head.header;
|
|
|
|
|
fileHeader->version = head.version;
|
|
|
|
|
fileHeader->ntoc = head.ntoc;
|
|
|
|
|
for (n = 0; n < fileHeader->ntoc; n++)
|
|
|
|
|
{
|
|
|
|
|
if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type))
|
|
|
|
|
break;
|
|
|
|
|
if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype))
|
|
|
|
|
break;
|
|
|
|
|
if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (n != fileHeader->ntoc)
|
|
|
|
|
{
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2006-10-10 14:57:16 -07:00
|
|
|
return NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
return fileHeader;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorUInt
|
|
|
|
|
_XcursorFileHeaderLength (XcursorFileHeader *fileHeader)
|
|
|
|
|
{
|
2011-09-16 21:26:17 -07:00
|
|
|
return (XCURSOR_FILE_HEADER_LEN +
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader->ntoc * XCURSOR_FILE_TOC_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
|
|
|
|
_XcursorWriteFileHeader (XcursorFile *file, XcursorFileHeader *fileHeader)
|
|
|
|
|
{
|
2021-03-11 17:18:31 -05:00
|
|
|
XcursorUInt toc;
|
2005-06-29 18:46:53 +00:00
|
|
|
|
|
|
|
|
if (!file || !fileHeader)
|
|
|
|
|
return XcursorFalse;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorWriteUInt (file, fileHeader->magic))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, fileHeader->header))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, fileHeader->version))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, fileHeader->ntoc))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
|
|
|
|
{
|
|
|
|
|
if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].type))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].subtype))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, fileHeader->tocs[toc].position))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
}
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
2011-09-16 21:26:17 -07:00
|
|
|
_XcursorSeekToToc (XcursorFile *file,
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorFileHeader *fileHeader,
|
|
|
|
|
int toc)
|
|
|
|
|
{
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !fileHeader || \
|
|
|
|
|
(*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF)
|
2003-11-14 16:48:48 +00:00
|
|
|
return XcursorFalse;
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
|
|
|
|
_XcursorFileReadChunkHeader (XcursorFile *file,
|
|
|
|
|
XcursorFileHeader *fileHeader,
|
|
|
|
|
int toc,
|
|
|
|
|
XcursorChunkHeader *chunkHeader)
|
|
|
|
|
{
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !fileHeader || !chunkHeader)
|
|
|
|
|
return XcursorFalse;
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorSeekToToc (file, fileHeader, toc))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorReadUInt (file, &chunkHeader->header))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorReadUInt (file, &chunkHeader->type))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorReadUInt (file, &chunkHeader->subtype))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorReadUInt (file, &chunkHeader->version))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
/* sanity check */
|
|
|
|
|
if (chunkHeader->type != fileHeader->tocs[toc].type ||
|
|
|
|
|
chunkHeader->subtype != fileHeader->tocs[toc].subtype)
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
|
|
|
|
_XcursorFileWriteChunkHeader (XcursorFile *file,
|
|
|
|
|
XcursorFileHeader *fileHeader,
|
|
|
|
|
int toc,
|
|
|
|
|
XcursorChunkHeader *chunkHeader)
|
|
|
|
|
{
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !fileHeader || !chunkHeader)
|
|
|
|
|
return XcursorFalse;
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorSeekToToc (file, fileHeader, toc))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, chunkHeader->header))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, chunkHeader->type))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, chunkHeader->subtype))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
if (!_XcursorWriteUInt (file, chunkHeader->version))
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a))
|
|
|
|
|
|
|
|
|
|
static XcursorDim
|
|
|
|
|
_XcursorFindBestSize (XcursorFileHeader *fileHeader,
|
|
|
|
|
XcursorDim size,
|
|
|
|
|
int *nsizesp)
|
|
|
|
|
{
|
2021-03-11 17:18:31 -05:00
|
|
|
XcursorUInt n;
|
2003-11-14 16:48:48 +00:00
|
|
|
int nsizes = 0;
|
|
|
|
|
XcursorDim bestSize = 0;
|
|
|
|
|
XcursorDim thisSize;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorFindBestSize) "(%p, %u, %p)\n",
|
|
|
|
|
(void*)fileHeader, size, (void*)nsizesp));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!fileHeader || !nsizesp)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnUint(0);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
for (n = 0; n < fileHeader->ntoc; n++)
|
|
|
|
|
{
|
|
|
|
|
if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE)
|
|
|
|
|
continue;
|
|
|
|
|
thisSize = fileHeader->tocs[n].subtype;
|
|
|
|
|
if (!bestSize || dist (thisSize, size) < dist (bestSize, size))
|
|
|
|
|
{
|
|
|
|
|
bestSize = thisSize;
|
|
|
|
|
nsizes = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (thisSize == bestSize)
|
|
|
|
|
nsizes++;
|
|
|
|
|
}
|
|
|
|
|
*nsizesp = nsizes;
|
2024-10-30 19:16:09 -04:00
|
|
|
returnUint(bestSize);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_XcursorFindImageToc (XcursorFileHeader *fileHeader,
|
|
|
|
|
XcursorDim size,
|
|
|
|
|
int count)
|
|
|
|
|
{
|
2021-03-11 17:18:31 -05:00
|
|
|
XcursorUInt toc;
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorDim thisSize;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorFindImageToc) "(%p, %u, %d)\n",
|
|
|
|
|
(void*)fileHeader, size, count));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
|
|
|
|
{
|
|
|
|
|
if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE)
|
|
|
|
|
continue;
|
|
|
|
|
thisSize = fileHeader->tocs[toc].subtype;
|
|
|
|
|
if (thisSize != size)
|
|
|
|
|
continue;
|
|
|
|
|
if (!count)
|
|
|
|
|
break;
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
if (toc == fileHeader->ntoc)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(-1);
|
|
|
|
|
returnCode((int) toc);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorImage *
|
2011-09-16 21:26:17 -07:00
|
|
|
_XcursorReadImage (XcursorFile *file,
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorFileHeader *fileHeader,
|
|
|
|
|
int toc)
|
|
|
|
|
{
|
|
|
|
|
XcursorChunkHeader chunkHeader;
|
|
|
|
|
XcursorImage head;
|
|
|
|
|
XcursorImage *image;
|
|
|
|
|
int n;
|
|
|
|
|
XcursorPixel *p;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorReadImage) "(%p, %p, %d)\n",
|
|
|
|
|
(void*)file, (void*)fileHeader, toc));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.width))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.height))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.xhot))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.yhot))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorReadUInt (file, &head.delay))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
/* sanity check data */
|
2017-10-21 23:47:52 +02:00
|
|
|
if (head.width > XCURSOR_IMAGE_MAX_SIZE ||
|
|
|
|
|
head.height > XCURSOR_IMAGE_MAX_SIZE)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (head.width == 0 || head.height == 0)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (head.xhot > head.width || head.yhot > head.height)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* Create the image and initialize it */
|
2021-03-10 19:36:04 -05:00
|
|
|
image = XcursorImageCreate ((int) head.width, (int) head.height);
|
2017-10-21 23:47:52 +02:00
|
|
|
if (image == NULL)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (chunkHeader.version < image->version)
|
|
|
|
|
image->version = chunkHeader.version;
|
|
|
|
|
image->size = chunkHeader.subtype;
|
|
|
|
|
image->xhot = head.xhot;
|
|
|
|
|
image->yhot = head.yhot;
|
|
|
|
|
image->delay = head.delay;
|
2021-03-10 19:36:04 -05:00
|
|
|
n = (int) (image->width * image->height);
|
2003-11-14 16:48:48 +00:00
|
|
|
p = image->pixels;
|
|
|
|
|
while (n--)
|
|
|
|
|
{
|
|
|
|
|
if (!_XcursorReadUInt (file, p))
|
|
|
|
|
{
|
|
|
|
|
XcursorImageDestroy (image);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
p++;
|
|
|
|
|
}
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(image);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorUInt
|
|
|
|
|
_XcursorImageLength (XcursorImage *image)
|
|
|
|
|
{
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorImageLength) "(%p)\n", (void*)image));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!image)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnUint(0);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
returnUint(XCURSOR_IMAGE_HEADER_LEN + (image->width * image->height) * 4);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
2011-09-16 21:26:17 -07:00
|
|
|
_XcursorWriteImage (XcursorFile *file,
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorFileHeader *fileHeader,
|
|
|
|
|
int toc,
|
|
|
|
|
XcursorImage *image)
|
|
|
|
|
{
|
|
|
|
|
XcursorChunkHeader chunkHeader;
|
|
|
|
|
int n;
|
|
|
|
|
XcursorPixel *p;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorWriteImage) "(%p, %p, %d, %p)\n",
|
|
|
|
|
(void*)file, (void*)fileHeader, toc, (void*)image));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !fileHeader || !image)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* sanity check data */
|
|
|
|
|
if (image->width > XCURSOR_IMAGE_MAX_SIZE ||
|
|
|
|
|
image->height > XCURSOR_IMAGE_MAX_SIZE)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (image->width == 0 || image->height == 0)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (image->xhot > image->width || image->yhot > image->height)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* write chunk header */
|
|
|
|
|
chunkHeader.header = XCURSOR_IMAGE_HEADER_LEN;
|
|
|
|
|
chunkHeader.type = XCURSOR_IMAGE_TYPE;
|
|
|
|
|
chunkHeader.subtype = image->size;
|
|
|
|
|
chunkHeader.version = XCURSOR_IMAGE_VERSION;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorFileWriteChunkHeader (file, fileHeader, toc, &chunkHeader))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* write extra image header fields */
|
|
|
|
|
if (!_XcursorWriteUInt (file, image->width))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorWriteUInt (file, image->height))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorWriteUInt (file, image->xhot))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorWriteUInt (file, image->yhot))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorWriteUInt (file, image->delay))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* write the image */
|
2021-03-10 19:36:04 -05:00
|
|
|
n = (int) (image->width * image->height);
|
2003-11-14 16:48:48 +00:00
|
|
|
p = image->pixels;
|
|
|
|
|
while (n--)
|
|
|
|
|
{
|
|
|
|
|
if (!_XcursorWriteUInt (file, *p))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
p++;
|
|
|
|
|
}
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorTrue);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorComment *
|
2011-09-16 21:26:17 -07:00
|
|
|
_XcursorReadComment (XcursorFile *file,
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorFileHeader *fileHeader,
|
|
|
|
|
int toc)
|
|
|
|
|
{
|
|
|
|
|
XcursorChunkHeader chunkHeader;
|
|
|
|
|
XcursorUInt length;
|
|
|
|
|
XcursorComment *comment;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorReadComment) "(%p, %p, %d)\n",
|
|
|
|
|
(void*)file, (void*)fileHeader, toc));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* read chunk header */
|
|
|
|
|
if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
/* read extra comment header fields */
|
|
|
|
|
if (!_XcursorReadUInt (file, &length))
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2021-03-10 19:36:04 -05:00
|
|
|
comment = XcursorCommentCreate (chunkHeader.subtype, (int) length);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!comment)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2021-03-10 19:36:04 -05:00
|
|
|
if (!_XcursorReadBytes (file, comment->comment, (int) length))
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
XcursorCommentDestroy (comment);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
comment->comment[length] = '\0';
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(comment);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorUInt
|
|
|
|
|
_XcursorCommentLength (XcursorComment *comment)
|
|
|
|
|
{
|
2021-03-10 19:36:04 -05:00
|
|
|
return XCURSOR_COMMENT_HEADER_LEN + (XcursorUInt) strlen (comment->comment);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XcursorBool
|
2011-09-16 21:26:17 -07:00
|
|
|
_XcursorWriteComment (XcursorFile *file,
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorFileHeader *fileHeader,
|
|
|
|
|
int toc,
|
|
|
|
|
XcursorComment *comment)
|
|
|
|
|
{
|
|
|
|
|
XcursorChunkHeader chunkHeader;
|
|
|
|
|
XcursorUInt length;
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !fileHeader || !comment || !comment->comment)
|
|
|
|
|
return XcursorFalse;
|
|
|
|
|
|
2021-03-10 19:36:04 -05:00
|
|
|
length = (XcursorUInt) strlen (comment->comment);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* sanity check data */
|
|
|
|
|
if (length > XCURSOR_COMMENT_MAX_LEN)
|
|
|
|
|
return XcursorFalse;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* read chunk header */
|
|
|
|
|
chunkHeader.header = XCURSOR_COMMENT_HEADER_LEN;
|
|
|
|
|
chunkHeader.type = XCURSOR_COMMENT_TYPE;
|
|
|
|
|
chunkHeader.subtype = comment->comment_type;
|
|
|
|
|
chunkHeader.version = XCURSOR_COMMENT_VERSION;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!_XcursorFileWriteChunkHeader (file, fileHeader, toc, &chunkHeader))
|
|
|
|
|
return XcursorFalse;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/* write extra comment header fields */
|
|
|
|
|
if (!_XcursorWriteUInt (file, length))
|
|
|
|
|
return XcursorFalse;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2021-03-10 19:36:04 -05:00
|
|
|
if (!_XcursorWriteBytes (file, comment->comment, (int) length))
|
2003-11-14 16:48:48 +00:00
|
|
|
return XcursorFalse;
|
|
|
|
|
return XcursorTrue;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-10 11:43:30 +08:00
|
|
|
static XcursorImage *
|
|
|
|
|
_XcursorResizeImage (XcursorImage *src, int size)
|
|
|
|
|
{
|
2024-10-27 10:12:52 -04:00
|
|
|
XcursorDim dest_y, dest_x;
|
2024-10-10 11:43:30 +08:00
|
|
|
double scale = (double) size / src->size;
|
2024-10-30 19:16:09 -04:00
|
|
|
XcursorImage *dest;
|
|
|
|
|
|
|
|
|
|
enterFunc((T_CALLED(_XcursorResizeImage) "(%p, %d)\n", (void*)src, size));
|
|
|
|
|
|
|
|
|
|
dest = XcursorImageCreate ((int) (src->width * scale),
|
|
|
|
|
(int) (src->height * scale));
|
2024-10-10 11:43:30 +08:00
|
|
|
if (!dest)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2024-10-10 11:43:30 +08:00
|
|
|
|
2024-10-27 10:12:52 -04:00
|
|
|
dest->size = (XcursorDim) size;
|
|
|
|
|
dest->xhot = (XcursorDim) (src->xhot * scale);
|
|
|
|
|
dest->yhot = (XcursorDim) (src->yhot * scale);
|
2024-10-10 11:43:30 +08:00
|
|
|
dest->delay = src->delay;
|
|
|
|
|
|
2024-10-27 06:40:18 -04:00
|
|
|
for (dest_y = 0; dest_y < dest->height; dest_y++)
|
2024-10-10 11:43:30 +08:00
|
|
|
{
|
2024-10-27 10:12:52 -04:00
|
|
|
XcursorDim src_y = (XcursorDim) (dest_y / scale);
|
|
|
|
|
XcursorPixel *src_row = src->pixels + (src_y * src->width);
|
|
|
|
|
XcursorPixel *dest_row = dest->pixels + (dest_y * dest->width);
|
2024-10-27 06:40:18 -04:00
|
|
|
for (dest_x = 0; dest_x < dest->width; dest_x++)
|
2024-10-10 11:43:30 +08:00
|
|
|
{
|
2024-10-27 10:12:52 -04:00
|
|
|
XcursorDim src_x = (XcursorDim) (dest_x / scale);
|
2024-10-10 11:43:30 +08:00
|
|
|
dest_row[dest_x] = src_row[src_x];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(dest);
|
2024-10-10 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
|
2024-10-29 16:10:51 -04:00
|
|
|
static XcursorImage *
|
|
|
|
|
_XcursorXcFileLoadImage (XcursorFile *file, int size, XcursorBool resize)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
XcursorFileHeader *fileHeader;
|
|
|
|
|
XcursorDim bestSize;
|
|
|
|
|
int nsize;
|
|
|
|
|
int toc;
|
|
|
|
|
XcursorImage *image;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorXcFileLoadImage) "(%p, %d, %d)\n",
|
|
|
|
|
(void*)file, size, resize));
|
|
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
if (size < 0)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader = _XcursorReadFileHeader (file);
|
|
|
|
|
if (!fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
|
|
|
|
|
if (!bestSize)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
toc = _XcursorFindImageToc (fileHeader, bestSize, 0);
|
|
|
|
|
if (toc < 0)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
image = _XcursorReadImage (file, fileHeader, toc);
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-10 11:43:30 +08:00
|
|
|
|
2024-11-04 04:00:20 -05:00
|
|
|
if (resize && image != NULL && (image->size != (XcursorDim) size))
|
2024-10-10 11:43:30 +08:00
|
|
|
{
|
|
|
|
|
XcursorImage *resized_image = _XcursorResizeImage (image, size);
|
|
|
|
|
XcursorImageDestroy (image);
|
|
|
|
|
image = resized_image;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(image);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-29 16:36:57 -04:00
|
|
|
XcursorImage *
|
|
|
|
|
XcursorXcFileLoadImage (XcursorFile *file, int size)
|
2024-10-29 16:10:51 -04:00
|
|
|
{
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorXcFileLoadImage) "(%p, %d)\n", (void*)file, size));
|
|
|
|
|
|
|
|
|
|
returnAddr(_XcursorXcFileLoadImage (file, size, XcursorFalse));
|
2024-10-29 16:10:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorImages *
|
|
|
|
|
_XcursorXcFileLoadImages (XcursorFile *file, int size, XcursorBool resize)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
XcursorFileHeader *fileHeader;
|
|
|
|
|
XcursorDim bestSize;
|
|
|
|
|
int nsize;
|
|
|
|
|
XcursorImages *images;
|
|
|
|
|
int n;
|
2024-10-10 11:43:30 +08:00
|
|
|
XcursorImage *image;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorXcFileLoadImages) "(%p, %d, %d)\n",
|
|
|
|
|
(void*)file, size, resize));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || size < 0)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader = _XcursorReadFileHeader (file);
|
|
|
|
|
if (!fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize);
|
|
|
|
|
if (!bestSize)
|
2006-06-03 10:23:57 +00:00
|
|
|
{
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2006-06-03 10:23:57 +00:00
|
|
|
}
|
2003-11-14 16:48:48 +00:00
|
|
|
images = XcursorImagesCreate (nsize);
|
|
|
|
|
if (!images)
|
2006-06-03 10:23:57 +00:00
|
|
|
{
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2006-06-03 10:23:57 +00:00
|
|
|
}
|
2003-11-14 16:48:48 +00:00
|
|
|
for (n = 0; n < nsize; n++)
|
|
|
|
|
{
|
2021-05-03 20:25:43 -04:00
|
|
|
int toc = _XcursorFindImageToc (fileHeader, bestSize, n);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (toc < 0)
|
|
|
|
|
break;
|
2024-10-27 19:17:19 -04:00
|
|
|
image = _XcursorReadImage (file, fileHeader, toc);
|
2024-10-10 11:43:30 +08:00
|
|
|
if (!image)
|
2003-11-14 16:48:48 +00:00
|
|
|
break;
|
2024-10-29 16:10:51 -04:00
|
|
|
if (resize && (image->size != (XcursorDim) size))
|
2024-10-10 11:43:30 +08:00
|
|
|
{
|
|
|
|
|
XcursorImage *resized_image = _XcursorResizeImage (image, size);
|
|
|
|
|
image = resized_image;
|
2024-10-27 19:17:19 -04:00
|
|
|
if (image == NULL)
|
|
|
|
|
break;
|
2024-10-10 11:43:30 +08:00
|
|
|
}
|
|
|
|
|
images->images[images->nimage] = image;
|
2003-11-14 16:48:48 +00:00
|
|
|
images->nimage++;
|
|
|
|
|
}
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-27 19:17:19 -04:00
|
|
|
if (images != NULL && images->nimage != nsize)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
XcursorImagesDestroy (images);
|
2006-10-10 14:57:16 -07:00
|
|
|
images = NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(images);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-29 16:36:57 -04:00
|
|
|
XcursorImages *
|
|
|
|
|
XcursorXcFileLoadImages (XcursorFile *file, int size)
|
2024-10-29 16:10:51 -04:00
|
|
|
{
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorXcFileLoadImages) "(%p, %d)\n", (void*)file, size));
|
|
|
|
|
|
|
|
|
|
returnAddr(_XcursorXcFileLoadImages (file, size, XcursorFalse));
|
2024-10-29 16:10:51 -04:00
|
|
|
}
|
|
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorImages *
|
|
|
|
|
XcursorXcFileLoadAllImages (XcursorFile *file)
|
|
|
|
|
{
|
|
|
|
|
XcursorFileHeader *fileHeader;
|
|
|
|
|
XcursorImage *image;
|
|
|
|
|
XcursorImages *images;
|
|
|
|
|
int nimage;
|
2021-03-11 17:18:31 -05:00
|
|
|
XcursorUInt n;
|
|
|
|
|
XcursorUInt toc;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorXcFileLoadAllImages) "(%p)\n", (void*)file));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader = _XcursorReadFileHeader (file);
|
|
|
|
|
if (!fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
nimage = 0;
|
|
|
|
|
for (n = 0; n < fileHeader->ntoc; n++)
|
|
|
|
|
{
|
|
|
|
|
switch (fileHeader->tocs[n].type) {
|
|
|
|
|
case XCURSOR_IMAGE_TYPE:
|
|
|
|
|
nimage++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
images = XcursorImagesCreate (nimage);
|
|
|
|
|
if (!images)
|
2011-04-01 12:15:46 +01:00
|
|
|
{
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2011-04-01 12:15:46 +01:00
|
|
|
}
|
2003-11-14 16:48:48 +00:00
|
|
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
|
|
|
|
{
|
|
|
|
|
switch (fileHeader->tocs[toc].type) {
|
|
|
|
|
case XCURSOR_IMAGE_TYPE:
|
2021-03-11 17:18:31 -05:00
|
|
|
image = _XcursorReadImage (file, fileHeader, (int) toc);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (image)
|
|
|
|
|
{
|
|
|
|
|
images->images[images->nimage] = image;
|
|
|
|
|
images->nimage++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
|
|
|
|
if (images->nimage != nimage)
|
|
|
|
|
{
|
|
|
|
|
XcursorImagesDestroy (images);
|
2006-10-10 14:57:16 -07:00
|
|
|
images = NULL;
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(images);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
|
|
|
|
XcursorXcFileLoad (XcursorFile *file,
|
|
|
|
|
XcursorComments **commentsp,
|
|
|
|
|
XcursorImages **imagesp)
|
|
|
|
|
{
|
|
|
|
|
XcursorFileHeader *fileHeader;
|
|
|
|
|
int nimage;
|
|
|
|
|
int ncomment;
|
|
|
|
|
XcursorImages *images;
|
|
|
|
|
XcursorImage *image;
|
|
|
|
|
XcursorComment *comment;
|
|
|
|
|
XcursorComments *comments;
|
2021-03-11 17:18:31 -05:00
|
|
|
XcursorUInt toc;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorXcFileLoad) "(%p, %p, %p)\n",
|
|
|
|
|
(void*)file, (void*)commentsp, (void*)imagesp));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2003-11-14 16:48:48 +00:00
|
|
|
fileHeader = _XcursorReadFileHeader (file);
|
|
|
|
|
if (!fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2003-11-14 16:48:48 +00:00
|
|
|
nimage = 0;
|
|
|
|
|
ncomment = 0;
|
|
|
|
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
|
|
|
|
{
|
|
|
|
|
switch (fileHeader->tocs[toc].type) {
|
|
|
|
|
case XCURSOR_COMMENT_TYPE:
|
|
|
|
|
ncomment++;
|
|
|
|
|
break;
|
|
|
|
|
case XCURSOR_IMAGE_TYPE:
|
|
|
|
|
nimage++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
images = XcursorImagesCreate (nimage);
|
|
|
|
|
if (!images)
|
2023-10-08 10:48:25 -07:00
|
|
|
{
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2023-10-08 10:48:25 -07:00
|
|
|
}
|
2003-11-14 16:48:48 +00:00
|
|
|
comments = XcursorCommentsCreate (ncomment);
|
|
|
|
|
if (!comments)
|
|
|
|
|
{
|
2023-10-08 10:48:25 -07:00
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorImagesDestroy (images);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
for (toc = 0; toc < fileHeader->ntoc; toc++)
|
|
|
|
|
{
|
|
|
|
|
switch (fileHeader->tocs[toc].type) {
|
|
|
|
|
case XCURSOR_COMMENT_TYPE:
|
2021-03-11 17:18:31 -05:00
|
|
|
comment = _XcursorReadComment (file, fileHeader, (int) toc);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (comment)
|
|
|
|
|
{
|
|
|
|
|
comments->comments[comments->ncomment] = comment;
|
|
|
|
|
comments->ncomment++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case XCURSOR_IMAGE_TYPE:
|
2021-03-11 17:18:31 -05:00
|
|
|
image = _XcursorReadImage (file, fileHeader, (int) toc);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (image)
|
|
|
|
|
{
|
|
|
|
|
images->images[images->nimage] = image;
|
|
|
|
|
images->nimage++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
|
|
|
|
if (images->nimage != nimage || comments->ncomment != ncomment)
|
|
|
|
|
{
|
|
|
|
|
XcursorImagesDestroy (images);
|
|
|
|
|
XcursorCommentsDestroy (comments);
|
2006-10-10 14:57:16 -07:00
|
|
|
images = NULL;
|
|
|
|
|
comments = NULL;
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
*imagesp = images;
|
|
|
|
|
*commentsp = comments;
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorTrue);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
2011-09-16 21:26:17 -07:00
|
|
|
XcursorXcFileSave (XcursorFile *file,
|
2003-11-14 16:48:48 +00:00
|
|
|
const XcursorComments *comments,
|
|
|
|
|
const XcursorImages *images)
|
|
|
|
|
{
|
|
|
|
|
XcursorFileHeader *fileHeader;
|
|
|
|
|
XcursorUInt position;
|
2024-11-03 17:36:03 -05:00
|
|
|
XcursorUInt n;
|
2003-11-14 16:48:48 +00:00
|
|
|
int toc;
|
2024-11-03 17:36:03 -05:00
|
|
|
XcursorUInt ncomment;
|
|
|
|
|
XcursorUInt nimage;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorXcFileSave) "(%p, %p, %p)\n",
|
|
|
|
|
(void*)file, (const void*)comments, (const void*)images));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !comments || !images)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnCode(XcursorFalse);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Caller may have tainted the counts.
|
|
|
|
|
*/
|
|
|
|
|
ncomment = (XcursorUInt)(comments->ncomment > 0 ? comments->ncomment : 0);
|
|
|
|
|
nimage = (XcursorUInt)(images->nimage > 0 ? images->nimage : 0);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-11-03 17:36:03 -05:00
|
|
|
fileHeader = _XcursorFileHeaderCreate (ncomment + nimage);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!fileHeader)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
position = _XcursorFileHeaderLength (fileHeader);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Compute the toc. Place the images before the comments
|
|
|
|
|
* as they're more often read
|
|
|
|
|
*/
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
toc = 0;
|
2024-11-03 17:36:03 -05:00
|
|
|
for (n = 0; n < nimage; n++)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
fileHeader->tocs[toc].type = XCURSOR_IMAGE_TYPE;
|
|
|
|
|
fileHeader->tocs[toc].subtype = images->images[n]->size;
|
|
|
|
|
fileHeader->tocs[toc].position = position;
|
|
|
|
|
position += _XcursorImageLength (images->images[n]);
|
|
|
|
|
toc++;
|
|
|
|
|
}
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2024-11-03 17:36:03 -05:00
|
|
|
for (n = 0; n < ncomment; n++)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
fileHeader->tocs[toc].type = XCURSOR_COMMENT_TYPE;
|
|
|
|
|
fileHeader->tocs[toc].subtype = comments->comments[n]->comment_type;
|
|
|
|
|
fileHeader->tocs[toc].position = position;
|
|
|
|
|
position += _XcursorCommentLength (comments->comments[n]);
|
|
|
|
|
toc++;
|
|
|
|
|
}
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/*
|
|
|
|
|
* Write the header and the toc
|
|
|
|
|
*/
|
|
|
|
|
if (!_XcursorWriteFileHeader (file, fileHeader))
|
|
|
|
|
goto bail;
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/*
|
|
|
|
|
* Write the images
|
|
|
|
|
*/
|
|
|
|
|
toc = 0;
|
2024-11-03 18:50:54 -05:00
|
|
|
for (n = 0; n < nimage; n++)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
if (!_XcursorWriteImage (file, fileHeader, toc, images->images[n]))
|
|
|
|
|
goto bail;
|
|
|
|
|
toc++;
|
|
|
|
|
}
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
/*
|
|
|
|
|
* Write the comments
|
|
|
|
|
*/
|
2024-11-03 18:50:54 -05:00
|
|
|
for (n = 0; n < ncomment; n++)
|
2003-11-14 16:48:48 +00:00
|
|
|
{
|
|
|
|
|
if (!_XcursorWriteComment (file, fileHeader, toc, comments->comments[n]))
|
|
|
|
|
goto bail;
|
|
|
|
|
toc++;
|
|
|
|
|
}
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorTrue);
|
|
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
bail:
|
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorFalse);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len)
|
|
|
|
|
{
|
|
|
|
|
FILE *f = file->closure;
|
2021-03-10 19:36:04 -05:00
|
|
|
return (int) fread (buf, 1, (size_t) len, f);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len)
|
|
|
|
|
{
|
|
|
|
|
FILE *f = file->closure;
|
2021-03-10 19:36:04 -05:00
|
|
|
return (int) fwrite (buf, 1, (size_t) len, f);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence)
|
|
|
|
|
{
|
|
|
|
|
FILE *f = file->closure;
|
|
|
|
|
return fseek (f, offset, whence);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file)
|
|
|
|
|
{
|
|
|
|
|
file->closure = stdfile;
|
|
|
|
|
file->read = _XcursorStdioFileRead;
|
|
|
|
|
file->write = _XcursorStdioFileWrite;
|
|
|
|
|
file->seek = _XcursorStdioFileSeek;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-29 16:36:57 -04:00
|
|
|
XcursorImage *
|
|
|
|
|
_XcursorFileLoadImage (FILE *file, int size, XcursorBool resize)
|
|
|
|
|
{
|
|
|
|
|
XcursorFile f;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorFileLoadImage) "(%p, %d, %d)\n", (void*)file, size, resize));
|
|
|
|
|
|
2024-10-29 16:36:57 -04:00
|
|
|
if (!file)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2024-10-29 16:36:57 -04:00
|
|
|
|
|
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(_XcursorXcFileLoadImage (&f, size, resize));
|
2024-10-29 16:36:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorImages *
|
|
|
|
|
_XcursorFileLoadImages (FILE *file, int size, XcursorBool resize)
|
|
|
|
|
{
|
|
|
|
|
XcursorFile f;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorFileLoadImages) "(%p, %d, %d)\n", (void*)file, size, resize));
|
|
|
|
|
|
2024-10-29 16:36:57 -04:00
|
|
|
if (!file)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2024-10-29 16:36:57 -04:00
|
|
|
|
|
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(_XcursorXcFileLoadImages (&f, size, resize));
|
2024-10-29 16:36:57 -04:00
|
|
|
}
|
|
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorImage *
|
|
|
|
|
XcursorFileLoadImage (FILE *file, int size)
|
|
|
|
|
{
|
|
|
|
|
XcursorFile f;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFileLoadImage) "(%p, %d)\n", (void*)file, size));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(XcursorXcFileLoadImage (&f, size));
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorImages *
|
|
|
|
|
XcursorFileLoadImages (FILE *file, int size)
|
|
|
|
|
{
|
|
|
|
|
XcursorFile f;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFileLoadImages) "(%p, %d)\n", (void*)file, size));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(XcursorXcFileLoadImages (&f, size));
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorImages *
|
|
|
|
|
XcursorFileLoadAllImages (FILE *file)
|
|
|
|
|
{
|
|
|
|
|
XcursorFile f;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFileLoadAllImages) "(%p)\n", (void*)file));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(XcursorXcFileLoadAllImages (&f));
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
2011-09-16 21:26:17 -07:00
|
|
|
XcursorFileLoad (FILE *file,
|
|
|
|
|
XcursorComments **commentsp,
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorImages **imagesp)
|
|
|
|
|
{
|
|
|
|
|
XcursorFile f;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFileLoad) "(%p, %p, %p)\n",
|
|
|
|
|
(void*)file, (void*)commentsp, (void*)imagesp));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !commentsp || !imagesp)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnCode(XcursorFalse);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorXcFileLoad (&f, commentsp, imagesp));
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
|
|
|
|
XcursorFileSaveImages (FILE *file, const XcursorImages *images)
|
|
|
|
|
{
|
2011-11-24 12:59:56 -08:00
|
|
|
XcursorComments *comments;
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorFile f;
|
|
|
|
|
XcursorBool ret;
|
2011-11-24 12:59:56 -08:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFileSaveImages) "(%p, %p)\n",
|
|
|
|
|
(void*)file, (const void*)images));
|
|
|
|
|
|
2011-11-24 12:59:56 -08:00
|
|
|
if (!file || !images)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2011-11-24 12:59:56 -08:00
|
|
|
if ((comments = XcursorCommentsCreate (0)) == NULL)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2003-11-14 16:48:48 +00:00
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
|
|
|
|
ret = XcursorXcFileSave (&f, comments, images) && fflush (file) != EOF;
|
|
|
|
|
XcursorCommentsDestroy (comments);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(ret);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
2011-09-16 21:26:17 -07:00
|
|
|
XcursorFileSave (FILE * file,
|
2003-11-14 16:48:48 +00:00
|
|
|
const XcursorComments *comments,
|
|
|
|
|
const XcursorImages *images)
|
|
|
|
|
{
|
|
|
|
|
XcursorFile f;
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorFileSave) "(%p, %p, %p)\n",
|
|
|
|
|
(void*)file, (const void*)comments, (const void*)images));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !comments || !images)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnCode(XcursorFalse);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
_XcursorStdioFileInitialize (file, &f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(XcursorXcFileSave (&f, comments, images) && fflush (file) != EOF);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorImage *
|
|
|
|
|
XcursorFilenameLoadImage (const char *file, int size)
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
XcursorImage *image;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFilenameLoadImage) "(\"%s\", %d)\n",
|
|
|
|
|
NonNull(file), size));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || size < 0)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2023-03-25 12:14:36 -07:00
|
|
|
f = fopen (file, "r" FOPEN_CLOEXEC);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!f)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
image = XcursorFileLoadImage (f, size);
|
|
|
|
|
fclose (f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(image);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-29 16:36:57 -04:00
|
|
|
XcursorImages *
|
|
|
|
|
_XcursorFilenameLoadImages (const char *file, int size, XcursorBool resize)
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
XcursorImages *images;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(_XcursorFilenameLoadImages) "(\"%s\", %d, %d)\n",
|
|
|
|
|
NonNull(file), size, resize));
|
|
|
|
|
|
2024-10-29 16:36:57 -04:00
|
|
|
if (!file || size < 0)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2024-10-29 16:36:57 -04:00
|
|
|
|
|
|
|
|
f = fopen (file, "r" FOPEN_CLOEXEC);
|
|
|
|
|
if (!f)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2024-10-29 16:36:57 -04:00
|
|
|
images = _XcursorFileLoadImages (f, size, resize);
|
|
|
|
|
fclose (f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(images);
|
2024-10-29 16:36:57 -04:00
|
|
|
}
|
|
|
|
|
|
2003-11-14 16:48:48 +00:00
|
|
|
XcursorImages *
|
|
|
|
|
XcursorFilenameLoadImages (const char *file, int size)
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
XcursorImages *images;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFilenameLoadImages) "(\"%s\", %d)\n",
|
|
|
|
|
NonNull(file), size));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || size < 0)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2011-09-16 21:26:17 -07:00
|
|
|
|
2023-03-25 12:14:36 -07:00
|
|
|
f = fopen (file, "r" FOPEN_CLOEXEC);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!f)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
images = XcursorFileLoadImages (f, size);
|
|
|
|
|
fclose (f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(images);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorImages *
|
|
|
|
|
XcursorFilenameLoadAllImages (const char *file)
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
XcursorImages *images;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFilenameLoadAllImages) "(\"%s\")\n",
|
|
|
|
|
NonNull(file)));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnAddr(NULL);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2023-03-25 12:14:36 -07:00
|
|
|
f = fopen (file, "r" FOPEN_CLOEXEC);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!f)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(NULL);
|
2003-11-14 16:48:48 +00:00
|
|
|
images = XcursorFileLoadAllImages (f);
|
|
|
|
|
fclose (f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnAddr(images);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
|
|
|
|
XcursorFilenameLoad (const char *file,
|
|
|
|
|
XcursorComments **commentsp,
|
|
|
|
|
XcursorImages **imagesp)
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
XcursorBool ret;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED() "(\"%s\", %p, %p)\n",
|
|
|
|
|
NonNull(file), (void*)commentsp, (void*)imagesp));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnCode(XcursorFalse);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2023-03-25 12:14:36 -07:00
|
|
|
f = fopen (file, "r" FOPEN_CLOEXEC);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!f)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2003-11-14 16:48:48 +00:00
|
|
|
ret = XcursorFileLoad (f, commentsp, imagesp);
|
|
|
|
|
fclose (f);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(ret);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
|
|
|
|
XcursorFilenameSaveImages (const char *file, const XcursorImages *images)
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
XcursorBool ret;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFilenameSaveImages) "(\"%s\", %p)\n",
|
|
|
|
|
NonNull(file), (const void*)images));
|
|
|
|
|
|
2005-06-29 18:46:53 +00:00
|
|
|
if (!file || !images)
|
2024-11-03 17:36:03 -05:00
|
|
|
returnCode(XcursorFalse);
|
2005-06-29 18:46:53 +00:00
|
|
|
|
2023-03-25 12:14:36 -07:00
|
|
|
f = fopen (file, "w" FOPEN_CLOEXEC);
|
2003-11-14 16:48:48 +00:00
|
|
|
if (!f)
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(0);
|
2003-11-14 16:48:48 +00:00
|
|
|
ret = XcursorFileSaveImages (f, images);
|
2024-10-30 19:16:09 -04:00
|
|
|
returnCode(fclose (f) != EOF && ret);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XcursorBool
|
2011-09-16 21:26:17 -07:00
|
|
|
XcursorFilenameSave (const char *file,
|
2003-11-14 16:48:48 +00:00
|
|
|
const XcursorComments *comments,
|
|
|
|
|
const XcursorImages *images)
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
XcursorBool ret;
|
|
|
|
|
|
2024-10-30 19:16:09 -04:00
|
|
|
enterFunc((T_CALLED(XcursorFilenameSave ) "(\"%s\", %p, %p)\n",
|
|
|
|
|
NonNull(file),
|
|
|
|
|
(const void *) comments,
|
|
|
|
|
(const void *) images));
|
|
|
|
|
|
|
|
|
|
if (!file || !comments || !images) {
|
2024-11-03 17:36:03 -05:00
|
|
|
ret = XcursorFalse;
|
2024-10-30 19:16:09 -04:00
|
|
|
} else {
|
|
|
|
|
f = fopen (file, "w" FOPEN_CLOEXEC);
|
|
|
|
|
if (!f) {
|
|
|
|
|
ret = 0;
|
|
|
|
|
} else {
|
|
|
|
|
ret = XcursorFileSave (f, comments, images);
|
|
|
|
|
ret = fclose (f) != EOF && ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
returnCode(ret);
|
2003-11-14 16:48:48 +00:00
|
|
|
}
|