xf86bigfont.c revision 4642e01f
1/*
2 * BIGFONT extension for sharing font metrics between clients (if possible)
3 * and for transmitting font metrics to clients in a compressed form.
4 *
5 * Copyright (c) 1999-2000  Bruno Haible
6 * Copyright (c) 1999-2000  The XFree86 Project, Inc.
7 */
8
9/* THIS IS NOT AN X CONSORTIUM STANDARD */
10
11/*
12 * Big fonts suffer from the following: All clients that have opened a
13 * font can access the complete glyph metrics array (the XFontStruct member
14 * `per_char') directly, without going through a macro. Moreover these
15 * glyph metrics are ink metrics, i.e. are not redundant even for a
16 * fixed-width font. For a Unicode font, the size of this array is 768 KB.
17 *
18 * Problems: 1. It eats a lot of memory in each client. 2. All this glyph
19 * metrics data is piped through the socket when the font is opened.
20 *
21 * This extension addresses these two problems for local clients, by using
22 * shared memory. It also addresses the second problem for non-local clients,
23 * by compressing the data before transmit by a factor of nearly 6.
24 *
25 * If you use this extension, your OS ought to nicely support shared memory.
26 * This means: Shared memory should be swappable to the swap, and the limits
27 * should be high enough (SHMMNI at least 64, SHMMAX at least 768 KB,
28 * SHMALL at least 48 MB). It is a plus if your OS allows shmat() calls
29 * on segments that have already been marked "removed", because it permits
30 * these segments to be cleaned up by the OS if the X server is killed with
31 * signal SIGKILL.
32 *
33 * This extension is transparently exploited by Xlib (functions XQueryFont,
34 * XLoadQueryFont).
35 */
36
37#ifdef HAVE_DIX_CONFIG_H
38#include <dix-config.h>
39#endif
40
41#include <sys/types.h>
42#ifdef HAS_SHM
43#if defined(linux) && (!defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 2)
44/* libc4 does not define __GNU_LIBRARY__, libc5 defines __GNU_LIBRARY__ as 1 */
45/* Linux libc4 and libc5 only (because glibc doesn't include kernel headers):
46   Linux 2.0.x and 2.2.x define SHMLBA as PAGE_SIZE, but forget to define
47   PAGE_SIZE. It is defined in <asm/page.h>. */
48#include <asm/page.h>
49#endif
50#ifdef SVR4
51#include <sys/sysmacros.h>
52#endif
53#if defined(__CYGWIN__) || defined(__SCO__)
54#include <sys/param.h>
55#include <sys/sysmacros.h>
56#endif
57#include <sys/ipc.h>
58#include <sys/shm.h>
59#include <sys/stat.h>
60#include <stdlib.h>
61#include <unistd.h>
62#include <time.h>
63#include <errno.h>
64#endif
65
66#include <X11/X.h>
67#include <X11/Xproto.h>
68#include "misc.h"
69#include "os.h"
70#include "dixstruct.h"
71#include "gcstruct.h"
72#include "dixfontstr.h"
73#include "extnsionst.h"
74
75#define _XF86BIGFONT_SERVER_
76#include <X11/extensions/xf86bigfstr.h>
77
78static void XF86BigfontResetProc(
79    ExtensionEntry *	/* extEntry */
80    );
81
82static DISPATCH_PROC(ProcXF86BigfontDispatch);
83static DISPATCH_PROC(ProcXF86BigfontQueryVersion);
84static DISPATCH_PROC(ProcXF86BigfontQueryFont);
85static DISPATCH_PROC(SProcXF86BigfontDispatch);
86static DISPATCH_PROC(SProcXF86BigfontQueryVersion);
87static DISPATCH_PROC(SProcXF86BigfontQueryFont);
88
89#ifdef HAS_SHM
90
91/* A random signature, transmitted to the clients so they can verify that the
92   shared memory segment they are attaching to was really established by the
93   X server they are talking to. */
94static CARD32 signature;
95
96/* Index for additional information stored in a FontRec's devPrivates array. */
97static int FontShmdescIndex;
98
99static unsigned int pagesize;
100
101static Bool badSysCall = FALSE;
102
103#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
104
105#include <sys/signal.h>
106
107static void
108SigSysHandler(
109     int signo)
110{
111    badSysCall = TRUE;
112}
113
114static Bool
115CheckForShmSyscall(void)
116{
117    void (*oldHandler)(int);
118    int shmid = -1;
119
120    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
121    oldHandler = signal(SIGSYS, SigSysHandler);
122
123    badSysCall = FALSE;
124    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
125    if (shmid != -1)
126    {
127        /* Successful allocation - clean up */
128	shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
129    }
130    else
131    {
132        /* Allocation failed */
133        badSysCall = TRUE;
134    }
135    signal(SIGSYS, oldHandler);
136    return (!badSysCall);
137}
138
139#define MUST_CHECK_FOR_SHM_SYSCALL
140
141#endif
142
143#endif
144
145void
146XFree86BigfontExtensionInit()
147{
148    if (AddExtension(XF86BIGFONTNAME,
149		     XF86BigfontNumberEvents,
150		     XF86BigfontNumberErrors,
151		     ProcXF86BigfontDispatch,
152		     SProcXF86BigfontDispatch,
153		     XF86BigfontResetProc,
154		     StandardMinorOpcode)) {
155#ifdef HAS_SHM
156#ifdef MUST_CHECK_FOR_SHM_SYSCALL
157	/*
158	 * Note: Local-clients will not be optimized without shared memory
159	 * support. Remote-client optimization does not depend on shared
160	 * memory support.  Thus, the extension is still registered even
161	 * when shared memory support is not functional.
162	 */
163	if (!CheckForShmSyscall()) {
164	    ErrorF(XF86BIGFONTNAME " extension local-client optimization disabled due to lack of shared memory support in the kernel\n");
165	    return;
166	}
167#endif
168
169	srand((unsigned int) time(NULL));
170	signature = ((unsigned int) (65536.0/(RAND_MAX+1.0) * rand()) << 16)
171	           + (unsigned int) (65536.0/(RAND_MAX+1.0) * rand());
172	/* fprintf(stderr, "signature = 0x%08X\n", signature); */
173
174	FontShmdescIndex = AllocateFontPrivateIndex();
175
176#if !defined(CSRG_BASED) && !defined(__CYGWIN__)
177	pagesize = SHMLBA;
178#else
179# ifdef _SC_PAGESIZE
180	pagesize = sysconf(_SC_PAGESIZE);
181# else
182	pagesize = getpagesize();
183# endif
184#endif
185#endif
186    }
187}
188
189
190/* ========== Management of shared memory segments ========== */
191
192#ifdef HAS_SHM
193
194#ifdef __linux__
195/* On Linux, shared memory marked as "removed" can still be attached.
196   Nice feature, because the kernel will automatically free the associated
197   storage when the server and all clients are gone. */
198#define EARLY_REMOVE
199#endif
200
201typedef struct _ShmDesc {
202    struct _ShmDesc *next;
203    struct _ShmDesc **prev;
204    int shmid;
205    char *attach_addr;
206} ShmDescRec, *ShmDescPtr;
207
208static ShmDescPtr ShmList = (ShmDescPtr) NULL;
209
210static ShmDescPtr
211shmalloc(
212    unsigned int size)
213{
214    ShmDescPtr pDesc;
215    int shmid;
216    char *addr;
217
218#ifdef MUST_CHECK_FOR_SHM_SYSCALL
219    if (pagesize == 0)
220	return (ShmDescPtr) NULL;
221#endif
222
223    /* On some older Linux systems, the number of shared memory segments
224       system-wide is 127. In Linux 2.4, it is 4095.
225       Therefore there is a tradeoff to be made between allocating a
226       shared memory segment on one hand, and allocating memory and piping
227       the glyph metrics on the other hand. If the glyph metrics size is
228       small, we prefer the traditional way. */
229    if (size < 3500)
230	return (ShmDescPtr) NULL;
231
232    pDesc = (ShmDescRec *) xalloc(sizeof(ShmDescRec));
233    if (!pDesc)
234	return (ShmDescPtr) NULL;
235
236    size = (size + pagesize-1) & -pagesize;
237    shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
238    if (shmid == -1) {
239	ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n",
240	       size, strerror(errno));
241	xfree(pDesc);
242	return (ShmDescPtr) NULL;
243    }
244
245    if ((addr = shmat(shmid, 0, 0)) == (char *)-1) {
246	ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n",
247	       size, strerror(errno));
248	shmctl(shmid, IPC_RMID, (void *) 0);
249	xfree(pDesc);
250	return (ShmDescPtr) NULL;
251    }
252
253#ifdef EARLY_REMOVE
254    shmctl(shmid, IPC_RMID, (void *) 0);
255#endif
256
257    pDesc->shmid = shmid;
258    pDesc->attach_addr = addr;
259    if (ShmList) ShmList->prev = &pDesc->next;
260    pDesc->next = ShmList;
261    pDesc->prev = &ShmList;
262    ShmList = pDesc;
263
264    return pDesc;
265}
266
267static void
268shmdealloc(
269    ShmDescPtr pDesc)
270{
271#ifndef EARLY_REMOVE
272    shmctl(pDesc->shmid, IPC_RMID, (void *) 0);
273#endif
274    shmdt(pDesc->attach_addr);
275
276    if (pDesc->next) pDesc->next->prev = pDesc->prev;
277    *pDesc->prev = pDesc->next;
278    xfree(pDesc);
279}
280
281#endif
282
283/* Called when a font is closed. */
284void
285XF86BigfontFreeFontShm(
286    FontPtr pFont)
287{
288#ifdef HAS_SHM
289    ShmDescPtr pDesc;
290
291    /* If during shutdown of the server, XF86BigfontCleanup() has already
292     * called shmdealloc() for all segments, we don't need to do it here.
293     */
294    if (!ShmList)
295	return;
296
297    pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
298    if (pDesc)
299	shmdealloc(pDesc);
300#endif
301}
302
303/* Called upon fatal signal. */
304void
305XF86BigfontCleanup()
306{
307#ifdef HAS_SHM
308    while (ShmList)
309	shmdealloc(ShmList);
310#endif
311}
312
313/* Called when a server generation dies. */
314static void
315XF86BigfontResetProc(
316    ExtensionEntry* extEntry)
317{
318    /* This function is normally called from CloseDownExtensions(), called
319     * from main(). It will be followed by a call to FreeAllResources(),
320     * which will call XF86BigfontFreeFontShm() for each font. Thus it
321     * appears that we do not need to do anything in this function. --
322     * But I prefer to write robust code, and not keep shared memory lying
323     * around when it's not needed any more. (Someone might close down the
324     * extension without calling FreeAllResources()...)
325     */
326    XF86BigfontCleanup();
327}
328
329
330/* ========== Handling of extension specific requests ========== */
331
332static int
333ProcXF86BigfontQueryVersion(
334    ClientPtr client)
335{
336    xXF86BigfontQueryVersionReply reply;
337
338    REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq);
339    reply.type = X_Reply;
340    reply.length = 0;
341    reply.sequenceNumber = client->sequence;
342    reply.majorVersion = XF86BIGFONT_MAJOR_VERSION;
343    reply.minorVersion = XF86BIGFONT_MINOR_VERSION;
344    reply.uid = geteuid();
345    reply.gid = getegid();
346#ifdef HAS_SHM
347    reply.signature = signature;
348#else
349    reply.signature = 0; /* This is redundant. Avoids uninitialized memory. */
350#endif
351    reply.capabilities =
352#ifdef HAS_SHM
353	(LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0)
354#else
355	0
356#endif
357	; /* may add more bits here in future versions */
358    if (client->swapped) {
359	char tmp;
360	swaps(&reply.sequenceNumber, tmp);
361	swapl(&reply.length, tmp);
362	swaps(&reply.majorVersion, tmp);
363	swaps(&reply.minorVersion, tmp);
364	swapl(&reply.uid, tmp);
365	swapl(&reply.gid, tmp);
366	swapl(&reply.signature, tmp);
367    }
368    WriteToClient(client,
369		  sizeof(xXF86BigfontQueryVersionReply), (char *)&reply);
370    return client->noClientException;
371}
372
373static void
374swapCharInfo(
375    xCharInfo *pCI)
376{
377    char tmp;
378
379    swaps(&pCI->leftSideBearing, tmp);
380    swaps(&pCI->rightSideBearing, tmp);
381    swaps(&pCI->characterWidth, tmp);
382    swaps(&pCI->ascent, tmp);
383    swaps(&pCI->descent, tmp);
384    swaps(&pCI->attributes, tmp);
385}
386
387/* static CARD32 hashCI (xCharInfo *p); */
388#define hashCI(p) \
389	(CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \
390	          (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \
391	          (p->characterWidth << 16) + \
392	          (p->ascent << 11) + (p->descent << 6)) ^ p->attributes)
393
394static int
395ProcXF86BigfontQueryFont(
396    ClientPtr client)
397{
398    FontPtr pFont;
399    REQUEST(xXF86BigfontQueryFontReq);
400    CARD32 stuff_flags;
401    xCharInfo* pmax;
402    xCharInfo* pmin;
403    int nCharInfos;
404    int shmid;
405#ifdef HAS_SHM
406    ShmDescPtr pDesc;
407#else
408#define pDesc 0
409#endif
410    xCharInfo* pCI;
411    CARD16* pIndex2UniqIndex;
412    CARD16* pUniqIndex2Index;
413    CARD32 nUniqCharInfos;
414
415#if 0
416    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
417#else
418    switch (client->req_len) {
419	case 2: /* client with version 1.0 libX11 */
420	    stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0);
421	    break;
422	case 3: /* client with version 1.1 libX11 */
423	    stuff_flags = stuff->flags;
424	    break;
425	default:
426	    return BadLength;
427    }
428#endif
429    client->errorValue = stuff->id;		/* EITHER font or gc */
430    pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT,
431					    DixGetAttrAccess);
432    if (!pFont) {
433	GC *pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC,
434						DixGetAttrAccess);
435        if (!pGC) {
436	    client->errorValue = stuff->id;
437            return BadFont;    /* procotol spec says only error is BadFont */
438	}
439	pFont = pGC->font;
440    }
441
442    pmax = FONTINKMAX(pFont);
443    pmin = FONTINKMIN(pFont);
444    nCharInfos =
445       (pmax->rightSideBearing == pmin->rightSideBearing
446        && pmax->leftSideBearing == pmin->leftSideBearing
447        && pmax->descent == pmin->descent
448        && pmax->ascent == pmin->ascent
449        && pmax->characterWidth == pmin->characterWidth)
450       ? 0 : N2dChars(pFont);
451    shmid = -1;
452    pCI = NULL;
453    pIndex2UniqIndex = NULL;
454    pUniqIndex2Index = NULL;
455    nUniqCharInfos = 0;
456
457    if (nCharInfos > 0) {
458#ifdef HAS_SHM
459	if (!badSysCall)
460	    pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
461	else
462	    pDesc = NULL;
463	if (pDesc) {
464	    pCI = (xCharInfo *) pDesc->attach_addr;
465	    if (stuff_flags & XF86Bigfont_FLAGS_Shm)
466		shmid = pDesc->shmid;
467	} else {
468	    if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall)
469		pDesc = shmalloc(nCharInfos * sizeof(xCharInfo)
470				 + sizeof(CARD32));
471	    if (pDesc) {
472		pCI = (xCharInfo *) pDesc->attach_addr;
473		shmid = pDesc->shmid;
474	    } else {
475#endif
476		pCI = (xCharInfo *)
477		      xalloc(nCharInfos * sizeof(xCharInfo));
478		if (!pCI)
479		    return BadAlloc;
480#ifdef HAS_SHM
481	    }
482#endif
483	    /* Fill nCharInfos starting at pCI. */
484	    {
485		xCharInfo* prCI = pCI;
486		int ninfos = 0;
487		int ncols = pFont->info.lastCol - pFont->info.firstCol + 1;
488		int row;
489		for (row = pFont->info.firstRow;
490		     row <= pFont->info.lastRow && ninfos < nCharInfos;
491		     row++) {
492		    unsigned char chars[512];
493		    xCharInfo* tmpCharInfos[256];
494		    unsigned long count;
495		    int col;
496		    unsigned long i;
497		    i = 0;
498		    for (col = pFont->info.firstCol;
499			 col <= pFont->info.lastCol;
500			 col++) {
501			chars[i++] = row;
502			chars[i++] = col;
503		    }
504		    (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
505					   &count, tmpCharInfos);
506		    for (i = 0; i < count && ninfos < nCharInfos; i++) {
507			*prCI++ = *tmpCharInfos[i];
508			ninfos++;
509		    }
510		}
511	    }
512#ifdef HAS_SHM
513	    if (pDesc && !badSysCall) {
514		*(CARD32 *)(pCI + nCharInfos) = signature;
515		if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) {
516		    shmdealloc(pDesc);
517		    return BadAlloc;
518		}
519	    }
520	}
521#endif
522	if (shmid == -1) {
523	    /* Cannot use shared memory, so remove-duplicates the xCharInfos
524	       using a temporary hash table. */
525	    /* Note that CARD16 is suitable as index type, because
526	       nCharInfos <= 0x10000. */
527	    CARD32 hashModulus;
528	    CARD16* pHash2UniqIndex;
529	    CARD16* pUniqIndex2NextUniqIndex;
530	    CARD32 NextIndex;
531	    CARD32 NextUniqIndex;
532	    CARD16* tmp;
533	    CARD32 i, j;
534
535	    hashModulus = 67;
536	    if (hashModulus > nCharInfos+1)
537		hashModulus = nCharInfos+1;
538
539	    tmp = (CARD16*)
540		  xalloc((4*nCharInfos+1) * sizeof(CARD16));
541	    if (!tmp) {
542		if (!pDesc) xfree(pCI);
543		return BadAlloc;
544	    }
545	    pIndex2UniqIndex = tmp;
546		/* nCharInfos elements */
547	    pUniqIndex2Index = tmp + nCharInfos;
548		/* max. nCharInfos elements */
549	    pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos;
550		/* max. nCharInfos elements */
551	    pHash2UniqIndex = tmp + 3*nCharInfos;
552		/* hashModulus (<= nCharInfos+1) elements */
553
554	    /* Note that we can use 0xffff as end-of-list indicator, because
555	       even if nCharInfos = 0x10000, 0xffff can not occur as valid
556	       entry before the last element has been inserted. And once the
557	       last element has been inserted, we don't need the hash table
558	       any more. */
559	    for (j = 0; j < hashModulus; j++)
560		pHash2UniqIndex[j] = (CARD16)(-1);
561
562	    NextUniqIndex = 0;
563	    for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) {
564		xCharInfo* p = &pCI[NextIndex];
565		CARD32 hashCode = hashCI(p) % hashModulus;
566		for (i = pHash2UniqIndex[hashCode];
567		     i != (CARD16)(-1);
568		     i = pUniqIndex2NextUniqIndex[i]) {
569		    j = pUniqIndex2Index[i];
570		    if (pCI[j].leftSideBearing == p->leftSideBearing
571			&& pCI[j].rightSideBearing == p->rightSideBearing
572			&& pCI[j].characterWidth == p->characterWidth
573			&& pCI[j].ascent == p->ascent
574			&& pCI[j].descent == p->descent
575			&& pCI[j].attributes == p->attributes)
576			break;
577		}
578		if (i != (CARD16)(-1)) {
579		    /* Found *p at Index j, UniqIndex i */
580		    pIndex2UniqIndex[NextIndex] = i;
581		} else {
582		    /* Allocate a new entry in the Uniq table */
583		    if (hashModulus <= 2*NextUniqIndex
584			&& hashModulus < nCharInfos+1) {
585			/* Time to increate hash table size */
586			hashModulus = 2*hashModulus+1;
587			if (hashModulus > nCharInfos+1)
588			    hashModulus = nCharInfos+1;
589			for (j = 0; j < hashModulus; j++)
590			    pHash2UniqIndex[j] = (CARD16)(-1);
591			for (i = 0; i < NextUniqIndex; i++)
592			    pUniqIndex2NextUniqIndex[i] = (CARD16)(-1);
593			for (i = 0; i < NextUniqIndex; i++) {
594			    j = pUniqIndex2Index[i];
595			    p = &pCI[j];
596			    hashCode = hashCI(p) % hashModulus;
597			    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
598			    pHash2UniqIndex[hashCode] = i;
599			}
600			p = &pCI[NextIndex];
601			hashCode = hashCI(p) % hashModulus;
602		    }
603		    i = NextUniqIndex++;
604		    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
605		    pHash2UniqIndex[hashCode] = i;
606		    pUniqIndex2Index[i] = NextIndex;
607		    pIndex2UniqIndex[NextIndex] = i;
608		}
609	    }
610	    nUniqCharInfos = NextUniqIndex;
611	    /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */
612	}
613    }
614
615    {
616	int nfontprops = pFont->info.nprops;
617	int rlength =
618	   sizeof(xXF86BigfontQueryFontReply)
619	   + nfontprops * sizeof(xFontProp)
620	   + (nCharInfos > 0 && shmid == -1
621	      ? nUniqCharInfos * sizeof(xCharInfo)
622	        + (nCharInfos+1)/2 * 2 * sizeof(CARD16)
623	      : 0);
624	xXF86BigfontQueryFontReply* reply =
625	   (xXF86BigfontQueryFontReply *) xalloc(rlength);
626	char* p;
627	if (!reply) {
628	    if (nCharInfos > 0) {
629		if (shmid == -1) xfree(pIndex2UniqIndex);
630		if (!pDesc) xfree(pCI);
631	    }
632	    return BadAlloc;
633	}
634	reply->type = X_Reply;
635	reply->length = (rlength - sizeof(xGenericReply)) >> 2;
636	reply->sequenceNumber = client->sequence;
637	reply->minBounds = pFont->info.ink_minbounds;
638	reply->maxBounds = pFont->info.ink_maxbounds;
639	reply->minCharOrByte2 = pFont->info.firstCol;
640	reply->maxCharOrByte2 = pFont->info.lastCol;
641	reply->defaultChar = pFont->info.defaultCh;
642	reply->nFontProps = pFont->info.nprops;
643	reply->drawDirection = pFont->info.drawDirection;
644	reply->minByte1 = pFont->info.firstRow;
645	reply->maxByte1 = pFont->info.lastRow;
646	reply->allCharsExist = pFont->info.allExist;
647	reply->fontAscent = pFont->info.fontAscent;
648	reply->fontDescent = pFont->info.fontDescent;
649	reply->nCharInfos = nCharInfos;
650        reply->nUniqCharInfos = nUniqCharInfos;
651	reply->shmid = shmid;
652	reply->shmsegoffset = 0;
653	if (client->swapped) {
654	    char tmp;
655	    swaps(&reply->sequenceNumber, tmp);
656	    swapl(&reply->length, tmp);
657	    swapCharInfo(&reply->minBounds);
658	    swapCharInfo(&reply->maxBounds);
659	    swaps(&reply->minCharOrByte2, tmp);
660	    swaps(&reply->maxCharOrByte2, tmp);
661	    swaps(&reply->defaultChar, tmp);
662	    swaps(&reply->nFontProps, tmp);
663	    swaps(&reply->fontAscent, tmp);
664	    swaps(&reply->fontDescent, tmp);
665	    swapl(&reply->nCharInfos, tmp);
666	    swapl(&reply->nUniqCharInfos, tmp);
667	    swapl(&reply->shmid, tmp);
668	    swapl(&reply->shmsegoffset, tmp);
669	}
670	p = (char*) &reply[1];
671	{
672	    FontPropPtr pFP;
673	    xFontProp* prFP;
674	    int i;
675	    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p;
676		 i < nfontprops;
677		 i++, pFP++, prFP++) {
678		prFP->name = pFP->name;
679		prFP->value = pFP->value;
680		if (client->swapped) {
681		    char tmp;
682		    swapl(&prFP->name, tmp);
683		    swapl(&prFP->value, tmp);
684		}
685	    }
686	    p = (char*) prFP;
687	}
688	if (nCharInfos > 0 && shmid == -1) {
689	    xCharInfo* pci;
690	    CARD16* ps;
691	    int i, j;
692	    pci = (xCharInfo*) p;
693	    for (i = 0; i < nUniqCharInfos; i++, pci++) {
694		*pci = pCI[pUniqIndex2Index[i]];
695		if (client->swapped)
696		    swapCharInfo(pci);
697	    }
698	    ps = (CARD16*) pci;
699	    for (j = 0; j < nCharInfos; j++, ps++) {
700		*ps = pIndex2UniqIndex[j];
701		if (client->swapped) {
702		    char tmp;
703		    swaps(ps, tmp);
704		}
705	    }
706	}
707	WriteToClient(client, rlength, (char *)reply);
708	xfree(reply);
709	if (nCharInfos > 0) {
710	    if (shmid == -1) xfree(pIndex2UniqIndex);
711	    if (!pDesc) xfree(pCI);
712	}
713	return (client->noClientException);
714    }
715}
716
717static int
718ProcXF86BigfontDispatch(
719    ClientPtr client)
720{
721    REQUEST(xReq);
722
723    switch (stuff->data) {
724	case X_XF86BigfontQueryVersion:
725	    return ProcXF86BigfontQueryVersion(client);
726	case X_XF86BigfontQueryFont:
727	    return ProcXF86BigfontQueryFont(client);
728	default:
729	    return BadRequest;
730    }
731}
732
733static int
734SProcXF86BigfontQueryVersion(
735    ClientPtr client)
736{
737    REQUEST(xXF86BigfontQueryVersionReq);
738    char tmp;
739
740    swaps(&stuff->length, tmp);
741    return ProcXF86BigfontQueryVersion(client);
742}
743
744static int
745SProcXF86BigfontQueryFont(
746    ClientPtr client)
747{
748    REQUEST(xXF86BigfontQueryFontReq);
749    char tmp;
750
751    swaps(&stuff->length, tmp);
752    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
753    swapl(&stuff->id, tmp);
754    return ProcXF86BigfontQueryFont(client);
755}
756
757static int
758SProcXF86BigfontDispatch(
759    ClientPtr client)
760{
761    REQUEST(xReq);
762
763    switch (stuff->data) {
764	case X_XF86BigfontQueryVersion:
765	    return SProcXF86BigfontQueryVersion(client);
766	case X_XF86BigfontQueryFont:
767	    return SProcXF86BigfontQueryFont(client);
768	default:
769	    return BadRequest;
770    }
771}
772