|
|
|
|
@ -25,17 +25,17 @@ |
|
|
|
|
|
|
|
|
|
#define _DEFAULT_SOURCE |
|
|
|
|
#include "xcursor.h" |
|
|
|
|
#include <dirent.h> |
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <dirent.h> |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* From libXcursor/include/X11/extensions/Xcursor.h |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#define XcursorTrue 1 |
|
|
|
|
#define XcursorFalse 0 |
|
|
|
|
#define XcursorTrue 1 |
|
|
|
|
#define XcursorFalse 0 |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Cursor files start with a header. The header |
|
|
|
|
@ -68,7 +68,7 @@ |
|
|
|
|
* CARD32 position absolute file position |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ |
|
|
|
|
#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Current Xcursor version number. Will be substituted by configure |
|
|
|
|
@ -78,32 +78,32 @@ |
|
|
|
|
#define XCURSOR_LIB_MAJOR 1 |
|
|
|
|
#define XCURSOR_LIB_MINOR 1 |
|
|
|
|
#define XCURSOR_LIB_REVISION 13 |
|
|
|
|
#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \ |
|
|
|
|
(XCURSOR_LIB_MINOR * 100) + \
|
|
|
|
|
(XCURSOR_LIB_REVISION)) |
|
|
|
|
#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + (XCURSOR_LIB_MINOR * 100) + (XCURSOR_LIB_REVISION)) |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This version number is stored in cursor files; changes to the |
|
|
|
|
* file format require updating this version number |
|
|
|
|
*/ |
|
|
|
|
#define XCURSOR_FILE_MAJOR 1 |
|
|
|
|
#define XCURSOR_FILE_MINOR 0 |
|
|
|
|
#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR)) |
|
|
|
|
#define XCURSOR_FILE_HEADER_LEN (4 * 4) |
|
|
|
|
#define XCURSOR_FILE_TOC_LEN (3 * 4) |
|
|
|
|
|
|
|
|
|
typedef struct _XcursorFileToc { |
|
|
|
|
XcursorUInt type; /* chunk type */ |
|
|
|
|
XcursorUInt subtype; /* subtype (size for images) */ |
|
|
|
|
XcursorUInt position; /* absolute position in file */ |
|
|
|
|
#define XCURSOR_FILE_MAJOR 1 |
|
|
|
|
#define XCURSOR_FILE_MINOR 0 |
|
|
|
|
#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR)) |
|
|
|
|
#define XCURSOR_FILE_HEADER_LEN (4 * 4) |
|
|
|
|
#define XCURSOR_FILE_TOC_LEN (3 * 4) |
|
|
|
|
|
|
|
|
|
typedef struct _XcursorFileToc |
|
|
|
|
{ |
|
|
|
|
XcursorUInt type; /* chunk type */ |
|
|
|
|
XcursorUInt subtype; /* subtype (size for images) */ |
|
|
|
|
XcursorUInt position; /* absolute position in file */ |
|
|
|
|
} XcursorFileToc; |
|
|
|
|
|
|
|
|
|
typedef struct _XcursorFileHeader { |
|
|
|
|
XcursorUInt magic; /* magic number */ |
|
|
|
|
XcursorUInt header; /* byte length of header */ |
|
|
|
|
XcursorUInt version; /* file version number */ |
|
|
|
|
XcursorUInt ntoc; /* number of toc entries */ |
|
|
|
|
XcursorFileToc *tocs; /* table of contents */ |
|
|
|
|
typedef struct _XcursorFileHeader |
|
|
|
|
{ |
|
|
|
|
XcursorUInt magic; /* magic number */ |
|
|
|
|
XcursorUInt header; /* byte length of header */ |
|
|
|
|
XcursorUInt version; /* file version number */ |
|
|
|
|
XcursorUInt ntoc; /* number of toc entries */ |
|
|
|
|
XcursorFileToc *tocs; /* table of contents */ |
|
|
|
|
} XcursorFileHeader; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@ -122,13 +122,14 @@ typedef struct _XcursorFileHeader { |
|
|
|
|
* CARD32 version chunk type version |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#define XCURSOR_CHUNK_HEADER_LEN (4 * 4) |
|
|
|
|
#define XCURSOR_CHUNK_HEADER_LEN (4 * 4) |
|
|
|
|
|
|
|
|
|
typedef struct _XcursorChunkHeader { |
|
|
|
|
XcursorUInt header; /* bytes in chunk header */ |
|
|
|
|
XcursorUInt type; /* chunk type */ |
|
|
|
|
XcursorUInt subtype; /* chunk subtype (size for images) */ |
|
|
|
|
XcursorUInt version; /* version of this type */ |
|
|
|
|
typedef struct _XcursorChunkHeader |
|
|
|
|
{ |
|
|
|
|
XcursorUInt header; /* bytes in chunk header */ |
|
|
|
|
XcursorUInt type; /* chunk type */ |
|
|
|
|
XcursorUInt subtype; /* chunk subtype (size for images) */ |
|
|
|
|
XcursorUInt version; /* version of this type */ |
|
|
|
|
} XcursorChunkHeader; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@ -145,18 +146,19 @@ typedef struct _XcursorChunkHeader { |
|
|
|
|
* LISTofCARD8 text UTF-8 encoded text |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#define XCURSOR_COMMENT_TYPE 0xfffe0001 |
|
|
|
|
#define XCURSOR_COMMENT_VERSION 1 |
|
|
|
|
#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4)) |
|
|
|
|
#define XCURSOR_COMMENT_COPYRIGHT 1 |
|
|
|
|
#define XCURSOR_COMMENT_LICENSE 2 |
|
|
|
|
#define XCURSOR_COMMENT_OTHER 3 |
|
|
|
|
#define XCURSOR_COMMENT_MAX_LEN 0x100000 |
|
|
|
|
|
|
|
|
|
typedef struct _XcursorComment { |
|
|
|
|
XcursorUInt version; |
|
|
|
|
XcursorUInt comment_type; |
|
|
|
|
char *comment; |
|
|
|
|
#define XCURSOR_COMMENT_TYPE 0xfffe0001 |
|
|
|
|
#define XCURSOR_COMMENT_VERSION 1 |
|
|
|
|
#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 * 4)) |
|
|
|
|
#define XCURSOR_COMMENT_COPYRIGHT 1 |
|
|
|
|
#define XCURSOR_COMMENT_LICENSE 2 |
|
|
|
|
#define XCURSOR_COMMENT_OTHER 3 |
|
|
|
|
#define XCURSOR_COMMENT_MAX_LEN 0x100000 |
|
|
|
|
|
|
|
|
|
typedef struct _XcursorComment |
|
|
|
|
{ |
|
|
|
|
XcursorUInt version; |
|
|
|
|
XcursorUInt comment_type; |
|
|
|
|
char *comment; |
|
|
|
|
} XcursorComment; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@ -175,14 +177,15 @@ typedef struct _XcursorComment { |
|
|
|
|
* LISTofCARD32 pixels ARGB pixels |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#define XCURSOR_IMAGE_TYPE 0xfffd0002 |
|
|
|
|
#define XCURSOR_IMAGE_VERSION 1 |
|
|
|
|
#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) |
|
|
|
|
#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ |
|
|
|
|
#define XCURSOR_IMAGE_TYPE 0xfffd0002 |
|
|
|
|
#define XCURSOR_IMAGE_VERSION 1 |
|
|
|
|
#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5 * 4)) |
|
|
|
|
#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ |
|
|
|
|
|
|
|
|
|
typedef struct _XcursorComments { |
|
|
|
|
int ncomment; /* number of comments */ |
|
|
|
|
XcursorComment **comments; /* array of XcursorComment pointers */ |
|
|
|
|
typedef struct _XcursorComments |
|
|
|
|
{ |
|
|
|
|
int ncomment; /* number of comments */ |
|
|
|
|
XcursorComment **comments; /* array of XcursorComment pointers */ |
|
|
|
|
} XcursorComments; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@ -190,21 +193,20 @@ typedef struct _XcursorComments { |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static XcursorImage * |
|
|
|
|
XcursorImageCreate (int width, int height) |
|
|
|
|
XcursorImageCreate(int width, int height) |
|
|
|
|
{ |
|
|
|
|
XcursorImage *image; |
|
|
|
|
XcursorImage *image; |
|
|
|
|
|
|
|
|
|
if (width < 0 || height < 0) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
image = malloc (sizeof (XcursorImage) + |
|
|
|
|
width * height * sizeof (XcursorPixel)); |
|
|
|
|
image = malloc(sizeof(XcursorImage) + width * height * sizeof(XcursorPixel)); |
|
|
|
|
if (!image) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
image->version = XCURSOR_IMAGE_VERSION; |
|
|
|
|
image->pixels = (XcursorPixel *) (image + 1); |
|
|
|
|
image->pixels = (XcursorPixel *)(image + 1); |
|
|
|
|
image->size = width > height ? width : height; |
|
|
|
|
image->width = width; |
|
|
|
|
image->height = height; |
|
|
|
|
@ -213,325 +215,305 @@ XcursorImageCreate (int width, int height) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
XcursorImageDestroy (XcursorImage *image) |
|
|
|
|
XcursorImageDestroy(XcursorImage *image) |
|
|
|
|
{ |
|
|
|
|
free (image); |
|
|
|
|
free(image); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static XcursorImages * |
|
|
|
|
XcursorImagesCreate (int size) |
|
|
|
|
XcursorImagesCreate(int size) |
|
|
|
|
{ |
|
|
|
|
XcursorImages *images; |
|
|
|
|
XcursorImages *images; |
|
|
|
|
|
|
|
|
|
images = malloc (sizeof (XcursorImages) + |
|
|
|
|
size * sizeof (XcursorImage *)); |
|
|
|
|
images = malloc(sizeof(XcursorImages) + size * sizeof(XcursorImage *)); |
|
|
|
|
if (!images) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
images->nimage = 0; |
|
|
|
|
images->images = (XcursorImage **) (images + 1); |
|
|
|
|
images->images = (XcursorImage **)(images + 1); |
|
|
|
|
return images; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
XcursorImagesDestroy (XcursorImages *images) |
|
|
|
|
void XcursorImagesDestroy(XcursorImages *images) |
|
|
|
|
{ |
|
|
|
|
int n; |
|
|
|
|
int n; |
|
|
|
|
|
|
|
|
|
if (!images) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
for (n = 0; n < images->nimage; n++) |
|
|
|
|
XcursorImageDestroy (images->images[n]); |
|
|
|
|
free (images); |
|
|
|
|
XcursorImageDestroy(images->images[n]); |
|
|
|
|
free(images); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static XcursorBool |
|
|
|
|
_XcursorReadUInt (XcursorFile *file, XcursorUInt *u) |
|
|
|
|
_XcursorReadUInt(XcursorFile *file, XcursorUInt *u) |
|
|
|
|
{ |
|
|
|
|
uint8_t bytes[4]; |
|
|
|
|
uint8_t bytes[4]; |
|
|
|
|
|
|
|
|
|
if (!file || !u) |
|
|
|
|
return XcursorFalse; |
|
|
|
|
|
|
|
|
|
if ((*file->read) (file, bytes, 4) != 4) |
|
|
|
|
return XcursorFalse; |
|
|
|
|
if ((*file->read)(file, bytes, 4) != 4) |
|
|
|
|
return XcursorFalse; |
|
|
|
|
|
|
|
|
|
*u = ((XcursorUInt)(bytes[0]) << 0) | |
|
|
|
|
((XcursorUInt)(bytes[1]) << 8) | |
|
|
|
|
((XcursorUInt)(bytes[2]) << 16) | |
|
|
|
|
((XcursorUInt)(bytes[3]) << 24); |
|
|
|
|
*u = ((XcursorUInt)(bytes[0]) << 0) | ((XcursorUInt)(bytes[1]) << 8) | ((XcursorUInt)(bytes[2]) << 16) | ((XcursorUInt)(bytes[3]) << 24); |
|
|
|
|
return XcursorTrue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader) |
|
|
|
|
_XcursorFileHeaderDestroy(XcursorFileHeader *fileHeader) |
|
|
|
|
{ |
|
|
|
|
free (fileHeader); |
|
|
|
|
free(fileHeader); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static XcursorFileHeader * |
|
|
|
|
_XcursorFileHeaderCreate (XcursorUInt ntoc) |
|
|
|
|
_XcursorFileHeaderCreate(XcursorUInt ntoc) |
|
|
|
|
{ |
|
|
|
|
XcursorFileHeader *fileHeader; |
|
|
|
|
XcursorFileHeader *fileHeader; |
|
|
|
|
|
|
|
|
|
if (ntoc > 0x10000) |
|
|
|
|
return NULL; |
|
|
|
|
fileHeader = malloc (sizeof (XcursorFileHeader) + |
|
|
|
|
ntoc * sizeof (XcursorFileToc)); |
|
|
|
|
return NULL; |
|
|
|
|
fileHeader = malloc(sizeof(XcursorFileHeader) + ntoc * sizeof(XcursorFileToc)); |
|
|
|
|
if (!fileHeader) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
fileHeader->magic = XCURSOR_MAGIC; |
|
|
|
|
fileHeader->header = XCURSOR_FILE_HEADER_LEN; |
|
|
|
|
fileHeader->version = XCURSOR_FILE_VERSION; |
|
|
|
|
fileHeader->ntoc = ntoc; |
|
|
|
|
fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1); |
|
|
|
|
fileHeader->tocs = (XcursorFileToc *)(fileHeader + 1); |
|
|
|
|
return fileHeader; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static XcursorFileHeader * |
|
|
|
|
_XcursorReadFileHeader (XcursorFile *file) |
|
|
|
|
_XcursorReadFileHeader(XcursorFile *file) |
|
|
|
|
{ |
|
|
|
|
XcursorFileHeader head, *fileHeader; |
|
|
|
|
XcursorUInt skip; |
|
|
|
|
unsigned int n; |
|
|
|
|
XcursorFileHeader head, *fileHeader; |
|
|
|
|
XcursorUInt skip; |
|
|
|
|
unsigned int n; |
|
|
|
|
|
|
|
|
|
if (!file) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
if (!_XcursorReadUInt (file, &head.magic)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.magic)) |
|
|
|
|
return NULL; |
|
|
|
|
if (head.magic != XCURSOR_MAGIC) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.header)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.version)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.ntoc)) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.header)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.version)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.ntoc)) |
|
|
|
|
return NULL; |
|
|
|
|
skip = head.header - XCURSOR_FILE_HEADER_LEN; |
|
|
|
|
if (skip) |
|
|
|
|
if (!(*file->skip) (file, skip)) |
|
|
|
|
return NULL; |
|
|
|
|
fileHeader = _XcursorFileHeaderCreate (head.ntoc); |
|
|
|
|
if (!(*file->skip)(file, skip)) |
|
|
|
|
return NULL; |
|
|
|
|
fileHeader = _XcursorFileHeaderCreate(head.ntoc); |
|
|
|
|
if (!fileHeader) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
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; |
|
|
|
|
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); |
|
|
|
|
return NULL; |
|
|
|
|
if (n != fileHeader->ntoc) { |
|
|
|
|
_XcursorFileHeaderDestroy(fileHeader); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
return fileHeader; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static XcursorBool |
|
|
|
|
_XcursorSeekToToc (XcursorFile *file, |
|
|
|
|
XcursorFileHeader *fileHeader, |
|
|
|
|
int toc) |
|
|
|
|
_XcursorSeekToToc(XcursorFile *file, |
|
|
|
|
XcursorFileHeader *fileHeader, |
|
|
|
|
int toc) |
|
|
|
|
{ |
|
|
|
|
if (!file || !fileHeader) |
|
|
|
|
return XcursorFalse; |
|
|
|
|
return (*file->seek) (file, fileHeader->tocs[toc].position); |
|
|
|
|
return (*file->seek)(file, fileHeader->tocs[toc].position); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static XcursorBool |
|
|
|
|
_XcursorFileReadChunkHeader (XcursorFile *file, |
|
|
|
|
XcursorFileHeader *fileHeader, |
|
|
|
|
int toc, |
|
|
|
|
XcursorChunkHeader *chunkHeader) |
|
|
|
|
_XcursorFileReadChunkHeader(XcursorFile *file, |
|
|
|
|
XcursorFileHeader *fileHeader, |
|
|
|
|
int toc, |
|
|
|
|
XcursorChunkHeader *chunkHeader) |
|
|
|
|
{ |
|
|
|
|
if (!file || !fileHeader || !chunkHeader) |
|
|
|
|
return XcursorFalse; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
if (chunkHeader->type != fileHeader->tocs[toc].type || chunkHeader->subtype != fileHeader->tocs[toc].subtype) |
|
|
|
|
return XcursorFalse; |
|
|
|
|
return XcursorTrue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) |
|
|
|
|
#define dist(a, b) ((a) > (b) ? (a) - (b) : (b) - (a)) |
|
|
|
|
|
|
|
|
|
static XcursorDim |
|
|
|
|
_XcursorFindBestSize (XcursorFileHeader *fileHeader, |
|
|
|
|
XcursorDim size, |
|
|
|
|
int *nsizesp) |
|
|
|
|
_XcursorFindBestSize(XcursorFileHeader *fileHeader, |
|
|
|
|
XcursorDim size, |
|
|
|
|
int *nsizesp) |
|
|
|
|
{ |
|
|
|
|
unsigned int n; |
|
|
|
|
int nsizes = 0; |
|
|
|
|
XcursorDim bestSize = 0; |
|
|
|
|
XcursorDim thisSize; |
|
|
|
|
int nsizes = 0; |
|
|
|
|
XcursorDim bestSize = 0; |
|
|
|
|
XcursorDim thisSize; |
|
|
|
|
|
|
|
|
|
if (!fileHeader || !nsizesp) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
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++; |
|
|
|
|
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; |
|
|
|
|
return bestSize; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
_XcursorFindImageToc (XcursorFileHeader *fileHeader, |
|
|
|
|
XcursorDim size, |
|
|
|
|
int count) |
|
|
|
|
_XcursorFindImageToc(XcursorFileHeader *fileHeader, |
|
|
|
|
XcursorDim size, |
|
|
|
|
int count) |
|
|
|
|
{ |
|
|
|
|
unsigned int toc; |
|
|
|
|
XcursorDim thisSize; |
|
|
|
|
unsigned int toc; |
|
|
|
|
XcursorDim thisSize; |
|
|
|
|
|
|
|
|
|
if (!fileHeader) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
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--; |
|
|
|
|
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) |
|
|
|
|
return -1; |
|
|
|
|
return -1; |
|
|
|
|
return toc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static XcursorImage * |
|
|
|
|
_XcursorReadImage (XcursorFile *file, |
|
|
|
|
XcursorFileHeader *fileHeader, |
|
|
|
|
int toc) |
|
|
|
|
_XcursorReadImage(XcursorFile *file, |
|
|
|
|
XcursorFileHeader *fileHeader, |
|
|
|
|
int toc) |
|
|
|
|
{ |
|
|
|
|
XcursorChunkHeader chunkHeader; |
|
|
|
|
XcursorImage head; |
|
|
|
|
XcursorImage *image; |
|
|
|
|
int n; |
|
|
|
|
XcursorPixel *p; |
|
|
|
|
XcursorChunkHeader chunkHeader; |
|
|
|
|
XcursorImage head; |
|
|
|
|
XcursorImage *image; |
|
|
|
|
int n; |
|
|
|
|
XcursorPixel *p; |
|
|
|
|
|
|
|
|
|
if (!file || !fileHeader) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.width)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.height)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.xhot)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.yhot)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt (file, &head.delay)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorFileReadChunkHeader(file, fileHeader, toc, &chunkHeader)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.width)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.height)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.xhot)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.yhot)) |
|
|
|
|
return NULL; |
|
|
|
|
if (!_XcursorReadUInt(file, &head.delay)) |
|
|
|
|
return NULL; |
|
|
|
|
/* sanity check data */ |
|
|
|
|
if (head.width > XCURSOR_IMAGE_MAX_SIZE || |
|
|
|
|
head.height > XCURSOR_IMAGE_MAX_SIZE) |
|
|
|
|
return NULL; |
|
|
|
|
if (head.width > XCURSOR_IMAGE_MAX_SIZE || head.height > XCURSOR_IMAGE_MAX_SIZE) |
|
|
|
|
return NULL; |
|
|
|
|
if (head.width == 0 || head.height == 0) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
if (head.xhot > head.width || head.yhot > head.height) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
/* Create the image and initialize it */ |
|
|
|
|
image = XcursorImageCreate (head.width, head.height); |
|
|
|
|
image = XcursorImageCreate(head.width, head.height); |
|
|
|
|
if (image == NULL) |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
if (chunkHeader.version < image->version) |
|
|
|
|
image->version = chunkHeader.version; |
|
|
|
|
image->version = chunkHeader.version; |
|
|
|
|
image->size = chunkHeader.subtype; |
|
|
|
|
image->xhot = head.xhot; |
|
|
|
|
image->yhot = head.yhot; |
|
|
|
|
image->delay = head.delay; |
|
|
|
|
n = image->width * image->height; |
|
|
|
|
p = image->pixels; |
|
|
|
|
while (n--) |
|
|
|
|
{ |
|
|
|
|
if (!_XcursorReadUInt (file, p)) |
|
|
|
|
{ |
|
|
|
|
XcursorImageDestroy (image); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
p++; |
|
|
|
|
while (n--) { |
|
|
|
|
if (!_XcursorReadUInt(file, p)) { |
|
|
|
|
XcursorImageDestroy(image); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
p++; |
|
|
|
|
} |
|
|
|
|
return image; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
XcursorImages * |
|
|
|
|
XcursorXcFileLoadImages (XcursorFile *file, int size) |
|
|
|
|
XcursorXcFileLoadImages(XcursorFile *file, int size) |
|
|
|
|
{ |
|
|
|
|
XcursorFileHeader *fileHeader; |
|
|
|
|
XcursorDim bestSize; |
|
|
|
|
int nsize; |
|
|
|
|
XcursorImages *images; |
|
|
|
|
int n; |
|
|
|
|
int toc; |
|
|
|
|
XcursorFileHeader *fileHeader; |
|
|
|
|
XcursorDim bestSize; |
|
|
|
|
int nsize; |
|
|
|
|
XcursorImages *images; |
|
|
|
|
int n; |
|
|
|
|
int toc; |
|
|
|
|
|
|
|
|
|
if (!file || size < 0) |
|
|
|
|
return NULL; |
|
|
|
|
fileHeader = _XcursorReadFileHeader (file); |
|
|
|
|
return NULL; |
|
|
|
|
fileHeader = _XcursorReadFileHeader(file); |
|
|
|
|
if (!fileHeader) |
|
|
|
|
return NULL; |
|
|
|
|
bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize); |
|
|
|
|
if (!bestSize) |
|
|
|
|
{ |
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader); |
|
|
|
|
return NULL; |
|
|
|
|
return NULL; |
|
|
|
|
bestSize = _XcursorFindBestSize(fileHeader, (XcursorDim)size, &nsize); |
|
|
|
|
if (!bestSize) { |
|
|
|
|
_XcursorFileHeaderDestroy(fileHeader); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
images = XcursorImagesCreate (nsize); |
|
|
|
|
if (!images) |
|
|
|
|
{ |
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader); |
|
|
|
|
return NULL; |
|
|
|
|
images = XcursorImagesCreate(nsize); |
|
|
|
|
if (!images) { |
|
|
|
|
_XcursorFileHeaderDestroy(fileHeader); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
for (n = 0; n < nsize; n++) |
|
|
|
|
{ |
|
|
|
|
toc = _XcursorFindImageToc (fileHeader, bestSize, n); |
|
|
|
|
if (toc < 0) |
|
|
|
|
break; |
|
|
|
|
images->images[images->nimage] = _XcursorReadImage (file, fileHeader, |
|
|
|
|
toc); |
|
|
|
|
if (!images->images[images->nimage]) |
|
|
|
|
break; |
|
|
|
|
images->nimage++; |
|
|
|
|
for (n = 0; n < nsize; n++) { |
|
|
|
|
toc = _XcursorFindImageToc(fileHeader, bestSize, n); |
|
|
|
|
if (toc < 0) |
|
|
|
|
break; |
|
|
|
|
images->images[images->nimage] = _XcursorReadImage(file, fileHeader, |
|
|
|
|
toc); |
|
|
|
|
if (!images->images[images->nimage]) |
|
|
|
|
break; |
|
|
|
|
images->nimage++; |
|
|
|
|
} |
|
|
|
|
_XcursorFileHeaderDestroy (fileHeader); |
|
|
|
|
if (images->nimage != nsize) |
|
|
|
|
{ |
|
|
|
|
XcursorImagesDestroy (images); |
|
|
|
|
images = NULL; |
|
|
|
|
_XcursorFileHeaderDestroy(fileHeader); |
|
|
|
|
if (images->nimage != nsize) { |
|
|
|
|
XcursorImagesDestroy(images); |
|
|
|
|
images = NULL; |
|
|
|
|
} |
|
|
|
|
return images; |
|
|
|
|
} |
|
|
|
|
|