#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <sys/types.h>
#ifdef HAS_SHM
#if defined(linux) && (!defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 2)
#include <asm/page.h>
#endif
#ifdef SVR4
#include <sys/sysmacros.h>
#endif
#if defined(__CYGWIN__) || defined(__SCO__)
#include <sys/param.h>
#include <sys/sysmacros.h>
#endif
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#endif
#include <X11/X.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "os.h"
#include "dixstruct.h"
#include "gcstruct.h"
#include "dixfontstr.h"
#include "extnsionst.h"
#define _XF86BIGFONT_SERVER_
#include <X11/extensions/xf86bigfstr.h>
static void XF86BigfontResetProc(
ExtensionEntry *
);
static DISPATCH_PROC(ProcXF86BigfontDispatch);
static DISPATCH_PROC(ProcXF86BigfontQueryVersion);
static DISPATCH_PROC(ProcXF86BigfontQueryFont);
static DISPATCH_PROC(SProcXF86BigfontDispatch);
static DISPATCH_PROC(SProcXF86BigfontQueryVersion);
static DISPATCH_PROC(SProcXF86BigfontQueryFont);
#ifdef HAS_SHM
static CARD32 signature;
static int FontShmdescIndex;
static unsigned int pagesize;
static Bool badSysCall = FALSE;
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
#include <sys/signal.h>
static void
SigSysHandler(
int signo)
{
badSysCall = TRUE;
}
static Bool
CheckForShmSyscall(void)
{
void (*oldHandler)(int);
int shmid = -1;
oldHandler = signal(SIGSYS, SigSysHandler);
badSysCall = FALSE;
shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
if (shmid != -1)
{
shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
}
else
{
badSysCall = TRUE;
}
signal(SIGSYS, oldHandler);
return (!badSysCall);
}
#define MUST_CHECK_FOR_SHM_SYSCALL
#endif
#endif
void
XFree86BigfontExtensionInit()
{
if (AddExtension(XF86BIGFONTNAME,
XF86BigfontNumberEvents,
XF86BigfontNumberErrors,
ProcXF86BigfontDispatch,
SProcXF86BigfontDispatch,
XF86BigfontResetProc,
StandardMinorOpcode)) {
#ifdef HAS_SHM
#ifdef MUST_CHECK_FOR_SHM_SYSCALL
if (!CheckForShmSyscall()) {
ErrorF(XF86BIGFONTNAME " extension local-client optimization disabled due to lack of shared memory support in the kernel\n");
return;
}
#endif
srand((unsigned int) time(NULL));
signature = ((unsigned int) (65536.0/(RAND_MAX+1.0) * rand()) << 16)
+ (unsigned int) (65536.0/(RAND_MAX+1.0) * rand());
FontShmdescIndex = AllocateFontPrivateIndex();
#if !defined(CSRG_BASED) && !defined(__CYGWIN__)
pagesize = SHMLBA;
#else
# ifdef _SC_PAGESIZE
pagesize = sysconf(_SC_PAGESIZE);
# else
pagesize = getpagesize();
# endif
#endif
#endif
}
}
#ifdef HAS_SHM
#ifdef __linux__
#define EARLY_REMOVE
#endif
typedef struct _ShmDesc {
struct _ShmDesc *next;
struct _ShmDesc **prev;
int shmid;
char *attach_addr;
} ShmDescRec, *ShmDescPtr;
static ShmDescPtr ShmList = (ShmDescPtr) NULL;
static ShmDescPtr
shmalloc(
unsigned int size)
{
ShmDescPtr pDesc;
int shmid;
char *addr;
#ifdef MUST_CHECK_FOR_SHM_SYSCALL
if (pagesize == 0)
return (ShmDescPtr) NULL;
#endif
if (size < 3500)
return (ShmDescPtr) NULL;
pDesc = (ShmDescRec *) xalloc(sizeof(ShmDescRec));
if (!pDesc)
return (ShmDescPtr) NULL;
size = (size + pagesize-1) & -pagesize;
shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
if (shmid == -1) {
ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n",
size, strerror(errno));
xfree(pDesc);
return (ShmDescPtr) NULL;
}
if ((addr = shmat(shmid, 0, 0)) == (char *)-1) {
ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n",
size, strerror(errno));
shmctl(shmid, IPC_RMID, (void *) 0);
xfree(pDesc);
return (ShmDescPtr) NULL;
}
#ifdef EARLY_REMOVE
shmctl(shmid, IPC_RMID, (void *) 0);
#endif
pDesc->shmid = shmid;
pDesc->attach_addr = addr;
if (ShmList) ShmList->prev = &pDesc->next;
pDesc->next = ShmList;
pDesc->prev = &ShmList;
ShmList = pDesc;
return pDesc;
}
static void
shmdealloc(
ShmDescPtr pDesc)
{
#ifndef EARLY_REMOVE
shmctl(pDesc->shmid, IPC_RMID, (void *) 0);
#endif
shmdt(pDesc->attach_addr);
if (pDesc->next) pDesc->next->prev = pDesc->prev;
*pDesc->prev = pDesc->next;
xfree(pDesc);
}
#endif
void
XF86BigfontFreeFontShm(
FontPtr pFont)
{
#ifdef HAS_SHM
ShmDescPtr pDesc;
if (!ShmList)
return;
pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
if (pDesc)
shmdealloc(pDesc);
#endif
}
void
XF86BigfontCleanup()
{
#ifdef HAS_SHM
while (ShmList)
shmdealloc(ShmList);
#endif
}
static void
XF86BigfontResetProc(
ExtensionEntry* extEntry)
{
XF86BigfontCleanup();
}
static int
ProcXF86BigfontQueryVersion(
ClientPtr client)
{
xXF86BigfontQueryVersionReply reply;
REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq);
reply.type = X_Reply;
reply.length = 0;
reply.sequenceNumber = client->sequence;
reply.majorVersion = XF86BIGFONT_MAJOR_VERSION;
reply.minorVersion = XF86BIGFONT_MINOR_VERSION;
reply.uid = geteuid();
reply.gid = getegid();
#ifdef HAS_SHM
reply.signature = signature;
#else
reply.signature = 0;
#endif
reply.capabilities =
#ifdef HAS_SHM
(LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0)
#else
0
#endif
;
if (client->swapped) {
char tmp;
swaps(&reply.sequenceNumber, tmp);
swapl(&reply.length, tmp);
swaps(&reply.majorVersion, tmp);
swaps(&reply.minorVersion, tmp);
swapl(&reply.uid, tmp);
swapl(&reply.gid, tmp);
swapl(&reply.signature, tmp);
}
WriteToClient(client,
sizeof(xXF86BigfontQueryVersionReply), (char *)&reply);
return client->noClientException;
}
static void
swapCharInfo(
xCharInfo *pCI)
{
char tmp;
swaps(&pCI->leftSideBearing, tmp);
swaps(&pCI->rightSideBearing, tmp);
swaps(&pCI->characterWidth, tmp);
swaps(&pCI->ascent, tmp);
swaps(&pCI->descent, tmp);
swaps(&pCI->attributes, tmp);
}
#define hashCI(p) \
(CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \
(p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \
(p->characterWidth << 16) + \
(p->ascent << 11) + (p->descent << 6)) ^ p->attributes)
static int
ProcXF86BigfontQueryFont(
ClientPtr client)
{
FontPtr pFont;
REQUEST(xXF86BigfontQueryFontReq);
CARD32 stuff_flags;
xCharInfo* pmax;
xCharInfo* pmin;
int nCharInfos;
int shmid;
#ifdef HAS_SHM
ShmDescPtr pDesc;
#else
#define pDesc 0
#endif
xCharInfo* pCI;
CARD16* pIndex2UniqIndex;
CARD16* pUniqIndex2Index;
CARD32 nUniqCharInfos;
#if 0
REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
#else
switch (client->req_len) {
case 2:
stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0);
break;
case 3:
stuff_flags = stuff->flags;
break;
default:
return BadLength;
}
#endif
client->errorValue = stuff->id;
pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT,
DixGetAttrAccess);
if (!pFont) {
GC *pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC,
DixGetAttrAccess);
if (!pGC) {
client->errorValue = stuff->id;
return BadFont;
}
pFont = pGC->font;
}
pmax = FONTINKMAX(pFont);
pmin = FONTINKMIN(pFont);
nCharInfos =
(pmax->rightSideBearing == pmin->rightSideBearing
&& pmax->leftSideBearing == pmin->leftSideBearing
&& pmax->descent == pmin->descent
&& pmax->ascent == pmin->ascent
&& pmax->characterWidth == pmin->characterWidth)
? 0 : N2dChars(pFont);
shmid = -1;
pCI = NULL;
pIndex2UniqIndex = NULL;
pUniqIndex2Index = NULL;
nUniqCharInfos = 0;
if (nCharInfos > 0) {
#ifdef HAS_SHM
if (!badSysCall)
pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
else
pDesc = NULL;
if (pDesc) {
pCI = (xCharInfo *) pDesc->attach_addr;
if (stuff_flags & XF86Bigfont_FLAGS_Shm)
shmid = pDesc->shmid;
} else {
if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall)
pDesc = shmalloc(nCharInfos * sizeof(xCharInfo)
+ sizeof(CARD32));
if (pDesc) {
pCI = (xCharInfo *) pDesc->attach_addr;
shmid = pDesc->shmid;
} else {
#endif
pCI = (xCharInfo *)
xalloc(nCharInfos * sizeof(xCharInfo));
if (!pCI)
return BadAlloc;
#ifdef HAS_SHM
}
#endif
{
xCharInfo* prCI = pCI;
int ninfos = 0;
int ncols = pFont->info.lastCol - pFont->info.firstCol + 1;
int row;
for (row = pFont->info.firstRow;
row <= pFont->info.lastRow && ninfos < nCharInfos;
row++) {
unsigned char chars[512];
xCharInfo* tmpCharInfos[256];
unsigned long count;
int col;
unsigned long i;
i = 0;
for (col = pFont->info.firstCol;
col <= pFont->info.lastCol;
col++) {
chars[i++] = row;
chars[i++] = col;
}
(*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
&count, tmpCharInfos);
for (i = 0; i < count && ninfos < nCharInfos; i++) {
*prCI++ = *tmpCharInfos[i];
ninfos++;
}
}
}
#ifdef HAS_SHM
if (pDesc && !badSysCall) {
*(CARD32 *)(pCI + nCharInfos) = signature;
if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) {
shmdealloc(pDesc);
return BadAlloc;
}
}
}
#endif
if (shmid == -1) {
CARD32 hashModulus;
CARD16* pHash2UniqIndex;
CARD16* pUniqIndex2NextUniqIndex;
CARD32 NextIndex;
CARD32 NextUniqIndex;
CARD16* tmp;
CARD32 i, j;
hashModulus = 67;
if (hashModulus > nCharInfos+1)
hashModulus = nCharInfos+1;
tmp = (CARD16*)
xalloc((4*nCharInfos+1) * sizeof(CARD16));
if (!tmp) {
if (!pDesc) xfree(pCI);
return BadAlloc;
}
pIndex2UniqIndex = tmp;
pUniqIndex2Index = tmp + nCharInfos;
pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos;
pHash2UniqIndex = tmp + 3*nCharInfos;
for (j = 0; j < hashModulus; j++)
pHash2UniqIndex[j] = (CARD16)(-1);
NextUniqIndex = 0;
for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) {
xCharInfo* p = &pCI[NextIndex];
CARD32 hashCode = hashCI(p) % hashModulus;
for (i = pHash2UniqIndex[hashCode];
i != (CARD16)(-1);
i = pUniqIndex2NextUniqIndex[i]) {
j = pUniqIndex2Index[i];
if (pCI[j].leftSideBearing == p->leftSideBearing
&& pCI[j].rightSideBearing == p->rightSideBearing
&& pCI[j].characterWidth == p->characterWidth
&& pCI[j].ascent == p->ascent
&& pCI[j].descent == p->descent
&& pCI[j].attributes == p->attributes)
break;
}
if (i != (CARD16)(-1)) {
pIndex2UniqIndex[NextIndex] = i;
} else {
if (hashModulus <= 2*NextUniqIndex
&& hashModulus < nCharInfos+1) {
hashModulus = 2*hashModulus+1;
if (hashModulus > nCharInfos+1)
hashModulus = nCharInfos+1;
for (j = 0; j < hashModulus; j++)
pHash2UniqIndex[j] = (CARD16)(-1);
for (i = 0; i < NextUniqIndex; i++)
pUniqIndex2NextUniqIndex[i] = (CARD16)(-1);
for (i = 0; i < NextUniqIndex; i++) {
j = pUniqIndex2Index[i];
p = &pCI[j];
hashCode = hashCI(p) % hashModulus;
pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
pHash2UniqIndex[hashCode] = i;
}
p = &pCI[NextIndex];
hashCode = hashCI(p) % hashModulus;
}
i = NextUniqIndex++;
pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
pHash2UniqIndex[hashCode] = i;
pUniqIndex2Index[i] = NextIndex;
pIndex2UniqIndex[NextIndex] = i;
}
}
nUniqCharInfos = NextUniqIndex;
}
}
{
int nfontprops = pFont->info.nprops;
int rlength =
sizeof(xXF86BigfontQueryFontReply)
+ nfontprops * sizeof(xFontProp)
+ (nCharInfos > 0 && shmid == -1
? nUniqCharInfos * sizeof(xCharInfo)
+ (nCharInfos+1)/2 * 2 * sizeof(CARD16)
: 0);
xXF86BigfontQueryFontReply* reply =
(xXF86BigfontQueryFontReply *) xalloc(rlength);
char* p;
if (!reply) {
if (nCharInfos > 0) {
if (shmid == -1) xfree(pIndex2UniqIndex);
if (!pDesc) xfree(pCI);
}
return BadAlloc;
}
reply->type = X_Reply;
reply->length = (rlength - sizeof(xGenericReply)) >> 2;
reply->sequenceNumber = client->sequence;
reply->minBounds = pFont->info.ink_minbounds;
reply->maxBounds = pFont->info.ink_maxbounds;
reply->minCharOrByte2 = pFont->info.firstCol;
reply->maxCharOrByte2 = pFont->info.lastCol;
reply->defaultChar = pFont->info.defaultCh;
reply->nFontProps = pFont->info.nprops;
reply->drawDirection = pFont->info.drawDirection;
reply->minByte1 = pFont->info.firstRow;
reply->maxByte1 = pFont->info.lastRow;
reply->allCharsExist = pFont->info.allExist;
reply->fontAscent = pFont->info.fontAscent;
reply->fontDescent = pFont->info.fontDescent;
reply->nCharInfos = nCharInfos;
reply->nUniqCharInfos = nUniqCharInfos;
reply->shmid = shmid;
reply->shmsegoffset = 0;
if (client->swapped) {
char tmp;
swaps(&reply->sequenceNumber, tmp);
swapl(&reply->length, tmp);
swapCharInfo(&reply->minBounds);
swapCharInfo(&reply->maxBounds);
swaps(&reply->minCharOrByte2, tmp);
swaps(&reply->maxCharOrByte2, tmp);
swaps(&reply->defaultChar, tmp);
swaps(&reply->nFontProps, tmp);
swaps(&reply->fontAscent, tmp);
swaps(&reply->fontDescent, tmp);
swapl(&reply->nCharInfos, tmp);
swapl(&reply->nUniqCharInfos, tmp);
swapl(&reply->shmid, tmp);
swapl(&reply->shmsegoffset, tmp);
}
p = (char*) &reply[1];
{
FontPropPtr pFP;
xFontProp* prFP;
int i;
for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p;
i < nfontprops;
i++, pFP++, prFP++) {
prFP->name = pFP->name;
prFP->value = pFP->value;
if (client->swapped) {
char tmp;
swapl(&prFP->name, tmp);
swapl(&prFP->value, tmp);
}
}
p = (char*) prFP;
}
if (nCharInfos > 0 && shmid == -1) {
xCharInfo* pci;
CARD16* ps;
int i, j;
pci = (xCharInfo*) p;
for (i = 0; i < nUniqCharInfos; i++, pci++) {
*pci = pCI[pUniqIndex2Index[i]];
if (client->swapped)
swapCharInfo(pci);
}
ps = (CARD16*) pci;
for (j = 0; j < nCharInfos; j++, ps++) {
*ps = pIndex2UniqIndex[j];
if (client->swapped) {
char tmp;
swaps(ps, tmp);
}
}
}
WriteToClient(client, rlength, (char *)reply);
xfree(reply);
if (nCharInfos > 0) {
if (shmid == -1) xfree(pIndex2UniqIndex);
if (!pDesc) xfree(pCI);
}
return (client->noClientException);
}
}
static int
ProcXF86BigfontDispatch(
ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data) {
case X_XF86BigfontQueryVersion:
return ProcXF86BigfontQueryVersion(client);
case X_XF86BigfontQueryFont:
return ProcXF86BigfontQueryFont(client);
default:
return BadRequest;
}
}
static int
SProcXF86BigfontQueryVersion(
ClientPtr client)
{
REQUEST(xXF86BigfontQueryVersionReq);
char tmp;
swaps(&stuff->length, tmp);
return ProcXF86BigfontQueryVersion(client);
}
static int
SProcXF86BigfontQueryFont(
ClientPtr client)
{
REQUEST(xXF86BigfontQueryFontReq);
char tmp;
swaps(&stuff->length, tmp);
REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
swapl(&stuff->id, tmp);
return ProcXF86BigfontQueryFont(client);
}
static int
SProcXF86BigfontDispatch(
ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data) {
case X_XF86BigfontQueryVersion:
return SProcXF86BigfontQueryVersion(client);
case X_XF86BigfontQueryFont:
return SProcXF86BigfontQueryFont(client);
default:
return BadRequest;
}
}