xserver-multidpi/lbx/lbxopts.c

807 lines
18 KiB
C

/* $Xorg: lbxopts.c,v 1.3 2000/08/17 19:53:31 cpqbld Exp $ */
/*
* Copyright 1994 Network Computing Devices, Inc.
*
* 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 Network Computing Devices, Inc. not be
* used in advertising or publicity pertaining to distribution of this
* software without specific, written prior permission.
*
* THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC.,
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
* LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK
* COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
* SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
* OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
* WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/* $XFree86: xc/programs/Xserver/lbx/lbxopts.c,v 1.5 2001/01/17 22:37:00 dawes Exp $ */
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#ifdef OPTDEBUG
#include <stdio.h>
#endif
#include <X11/X.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "colormapst.h"
#include "propertyst.h"
#include "lbxserve.h"
#include <X11/extensions/lbxstr.h>
#include <X11/extensions/lbximage.h>
#include <X11/extensions/lbxopts.h>
#include "lbxsrvopts.h"
#ifndef NO_ZLIB
#include <X11/extensions/lbxzlib.h>
#endif /* NO_ZLIB */
static int LbxProxyDeltaOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
static int LbxServerDeltaOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
static int LbxDeltaOpt ( unsigned char *popt, int optlen,
unsigned char *preply, short *pn, short *pmaxlen );
static int LbxStreamCompOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
static int ZlibParse ( LbxNegOptsPtr pno, unsigned char *popt, int optlen,
unsigned char *preply );
static int LbxMessageCompOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
static int LbxUseTagsOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
static int LbxBitmapCompOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
static int LbxPixmapCompOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
static int MergeDepths ( int *depths, LbxPixmapCompMethod *method );
static int LbxCmapAllOpt ( LbxNegOptsPtr pno, unsigned char *popt,
int optlen, unsigned char *preply );
/*
* List of LBX options we recognize and are willing to negotiate
*/
static struct _LbxOptionParser {
CARD8 optcode;
int (*parser)(LbxNegOptsPtr, unsigned char *,
int, unsigned char *);
} LbxOptions[] = {
{ LBX_OPT_DELTA_PROXY, LbxProxyDeltaOpt },
{ LBX_OPT_DELTA_SERVER, LbxServerDeltaOpt },
{ LBX_OPT_STREAM_COMP, LbxStreamCompOpt },
{ LBX_OPT_BITMAP_COMP, LbxBitmapCompOpt },
{ LBX_OPT_PIXMAP_COMP, LbxPixmapCompOpt },
{ LBX_OPT_MSG_COMP, LbxMessageCompOpt },
{ LBX_OPT_USE_TAGS, LbxUseTagsOpt },
{ LBX_OPT_CMAP_ALL, LbxCmapAllOpt }
};
#define LBX_N_OPTS (sizeof(LbxOptions) / sizeof(struct _LbxOptionParser))
/*
* Set option defaults
*/
void
LbxOptionInit(LbxNegOptsPtr pno)
{
bzero(pno, sizeof(LbxNegOptsRec));
pno->proxyDeltaN = pno->serverDeltaN = LBX_OPT_DELTA_NCACHE_DFLT;
pno->proxyDeltaMaxLen = pno->serverDeltaMaxLen = LBX_OPT_DELTA_MSGLEN_DFLT;
pno->squish = TRUE;
pno->numBitmapCompMethods = 0;
pno->bitmapCompMethods = NULL;
pno->numPixmapCompMethods = 0;
pno->pixmapCompMethods = NULL;
pno->pixmapCompDepths = NULL;
pno->useTags = TRUE;
}
int
LbxOptionParse(LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
int i;
int nopts = *popt++;
unsigned char *pout = preply;
for (i = 0; i < nopts; i++) {
int j;
int len;
int hdrlen;
int replylen;
LBX_OPT_DECODE_LEN(popt + 1, len, hdrlen);
if (len < ++hdrlen || len > optlen) {
#ifdef OPTDEBUG
fprintf(stderr, "bad option length, len = %d, hdrlen = %d, optlen = %d\n", len, hdrlen, optlen);
#endif
return -1;
}
for (j = 0; j < LBX_N_OPTS; j++) {
if (popt[0] == LbxOptions[j].optcode) {
replylen = (*LbxOptions[j].parser)(pno,
popt + hdrlen,
len - hdrlen,
pout + LBX_OPT_SMALLHDR_LEN);
if (replylen < 0)
return -1;
else if (replylen > 0) {
/*
* None of the current options require big headers,
* so this works for now.
*/
*pout++ = i;
*pout++ = LBX_OPT_SMALLHDR_LEN + replylen;
pout += replylen;
pno->nopts++;
}
break;
}
}
optlen -= len;
popt += len;
}
return (pout - preply);
}
static int
LbxProxyDeltaOpt(LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
return LbxDeltaOpt(popt, optlen, preply,
&pno->proxyDeltaN, &pno->proxyDeltaMaxLen);
}
static int
LbxServerDeltaOpt(LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
return LbxDeltaOpt(popt, optlen, preply,
&pno->serverDeltaN, &pno->serverDeltaMaxLen);
}
static int
LbxDeltaOpt(unsigned char *popt,
int optlen,
unsigned char *preply,
short *pn,
short *pmaxlen)
{
short n;
short maxlen;
/*
* If there's more data than we expect, we just ignore it.
*/
if (optlen < LBX_OPT_DELTA_REQLEN) {
#ifdef OPTDEBUG
fprintf(stderr, "bad delta option length = %d\n", optlen);
#endif
return -1;
}
/*
* Accept whatever value the proxy prefers, so skip the
* min/max offerings. Note that the max message len value is
* encoded as the number of 4-byte values.
*/
popt += 2;
n = *popt++;
popt += 2;
maxlen = *popt++;
if ((maxlen <<= 2) == 0)
n = 0;
else if (maxlen < 32) {
#ifdef OPTDEBUG
fprintf(stderr, "bad delta max msg length %d\n", maxlen);
#endif
return -1;
}
/*
* Put the response in the reply buffer
*/
*preply++ = n;
*preply++ = maxlen >> 2;
*pn = n;
*pmaxlen = maxlen;
return LBX_OPT_DELTA_REPLYLEN;
}
static struct _LbxStreamCompParser {
int typelen;
char *type;
int (*parser)(LbxNegOptsPtr, unsigned char *,
int, unsigned char *);
} LbxStreamComp[] = {
#ifndef NO_ZLIB
{ ZLIB_STRCOMP_OPT_LEN, ZLIB_STRCOMP_OPT, ZlibParse },
#endif /* NO_ZLIB */
};
#define LBX_N_STRCOMP \
(sizeof(LbxStreamComp) / sizeof(struct _LbxStreamCompParser))
static int
LbxStreamCompOpt(LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
int i;
int typelen;
int nopts = *popt++;
for (i = 0; i < nopts; i++) {
int j;
int len;
int lensize;
int replylen;
typelen = popt[0];
for (j = 0; j < LBX_N_STRCOMP; j++) {
if (typelen == LbxStreamComp[j].typelen &&
!strncmp((char *) popt + 1, LbxStreamComp[j].type, typelen))
break;
}
popt += 1 + typelen;
optlen -= 1 + typelen;
LBX_OPT_DECODE_LEN(popt, len, lensize);
if (j < LBX_N_STRCOMP) {
if (len > optlen)
return -1;
replylen = (*LbxStreamComp[j].parser)(pno,
popt + lensize,
len - lensize,
preply + 1);
if (replylen == -1)
return -1;
else if (replylen >= 0) {
*preply = i;
return replylen + 1;
}
}
optlen -= len;
popt += len;
}
return 0;
}
static int
ZlibParse(LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
int level; /* compression level */
if (*popt++ != 1) /* length should be 1 */
return (-1);
level = *popt;
if (level < 1 || level > 9)
return (-1);
pno->streamOpts.streamCompInit =
(LbxStreamCompHandle (*)(int, pointer))ZlibInit;
pno->streamOpts.streamCompArg = (pointer)(long)level;
pno->streamOpts.streamCompStuffInput = ZlibStuffInput;
pno->streamOpts.streamCompInputAvail = ZlibInputAvail;
pno->streamOpts.streamCompFlush = ZlibFlush;
pno->streamOpts.streamCompRead = ZlibRead;
pno->streamOpts.streamCompWriteV = ZlibWriteV;
pno->streamOpts.streamCompOn = ZlibCompressOn;
pno->streamOpts.streamCompOff = ZlibCompressOff;
pno->streamOpts.streamCompFreeHandle =
(void (*)(LbxStreamCompHandle))ZlibFree;
return (0);
}
static int
LbxMessageCompOpt(LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
if (optlen == 0) {
#ifdef OPTDEBUG
fprintf(stderr, "bad message-comp option length specified %d\n", optlen);
#endif
return -1;
}
pno->squish = *preply = *popt;
return 1;
}
static int
LbxUseTagsOpt(LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
if (optlen == 0) {
#ifdef OPTDEBUG
fprintf(stderr, "bad use-tags option length specified %d\n", optlen);
#endif
return -1;
}
pno->useTags = *preply = *popt;
return 1;
}
/*
* Option negotiation for image compression
*/
LbxBitmapCompMethod
LbxBitmapCompMethods [] = {
{
"XC-FaxG42D", /* compression method name */
0, /* inited */
2, /* method opcode */
NULL, /* init function */
LbxImageEncodeFaxG42D, /* encode function */
LbxImageDecodeFaxG42D /* decode function */
}
};
#define NUM_BITMAP_METHODS \
(sizeof (LbxBitmapCompMethods) / sizeof (LbxBitmapCompMethod))
#if 1
/*
* Currently, we don't support any pixmap compression algorithms
* because regular stream compression does much better than PackBits.
* If we want to plug in a better pixmap image compression algorithm,
* it would go here.
*/
#define NUM_PIXMAP_METHODS 0
LbxPixmapCompMethod LbxPixmapCompMethods [1]; /* dummy */
#else
LbxPixmapCompMethod
LbxPixmapCompMethods [] = {
{
"XC-PackBits", /* compression method name */
1 << ZPixmap, /* formats supported */
1, {8}, /* depths supported */
0, /* inited */
1, /* method opcode */
NULL, /* init function */
LbxImageEncodePackBits, /* encode function */
LbxImageDecodePackBits /* decode function */
}
};
#define NUM_PIXMAP_METHODS \
(sizeof (LbxPixmapCompMethods) / sizeof (LbxPixmapCompMethod))
#endif
static int
LbxImageCompOpt (Bool pixmap,
LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
unsigned char *preplyStart = preply;
int numMethods = *popt++;
unsigned char *myIndices, *hisIndices;
unsigned int *retFormats = NULL;
int **retDepths = NULL;
int replyCount = 0;
int status, i, j;
if (numMethods == 0)
{
if (pixmap)
pno->numPixmapCompMethods = 0;
else
pno->numBitmapCompMethods = 0;
*preply++ = 0;
return (1);
}
myIndices = (unsigned char *) xalloc (numMethods);
hisIndices = (unsigned char *) xalloc (numMethods);
if (!myIndices || !hisIndices)
{
if (myIndices)
xfree (myIndices);
if (hisIndices)
xfree (hisIndices);
return -1;
}
if (pixmap)
{
retFormats = (unsigned *) xalloc (numMethods);
retDepths = (int **) xalloc (numMethods * sizeof (int *));
if (!retFormats || !retDepths)
{
if (retFormats)
xfree (retFormats);
if (retDepths)
xfree (retDepths);
xfree (myIndices);
xfree (hisIndices);
return -1;
}
}
/*
* For each method in the list sent by the proxy, see if the server
* supports this method. If YES, update the following lists:
*
* myIndices[] is a list of indices into the server's
* LbxBit[Pix]mapCompMethods table.
*
* hisIndices[] is a list of indices into the list of
* method names sent by the proxy.
*
* retFormats[] indicates for each pixmap compression method,
* the pixmap formats supported.
*
* retDepths[] indicates for each pixmap compression method,
* the pixmap depths supported.
*/
for (i = 0; i < numMethods; i++)
{
unsigned int formatMask = 0, newFormatMask = 0;
int depthCount, *depths = NULL, len;
int freeDepths;
char *methodName;
freeDepths = 0;
len = *popt++;
methodName = (char *) popt;
popt += len;
if (pixmap)
{
formatMask = *popt++;
depthCount = *popt++;
depths = (int *) xalloc ((depthCount + 1) * sizeof (int));
freeDepths = 1;
depths[0] = depthCount;
for (j = 1; j <= depthCount; j++)
depths[j] = *popt++;
}
for (j = 0;
j < (pixmap ? NUM_PIXMAP_METHODS : NUM_BITMAP_METHODS); j++)
{
status = strncmp (methodName,
(pixmap ? LbxPixmapCompMethods[j].methodName :
LbxBitmapCompMethods[j].methodName),
len);
if (status == 0 && pixmap)
{
newFormatMask =
formatMask & LbxPixmapCompMethods[j].formatMask;
depthCount = MergeDepths (depths, &LbxPixmapCompMethods[j]);
if (newFormatMask == 0 || depthCount == 0)
status = 1;
}
if (status == 0)
{
myIndices[replyCount] = j;
hisIndices[replyCount] = i;
if (pixmap)
{
retFormats[replyCount] = newFormatMask;
retDepths[replyCount] = depths;
freeDepths = 0;
}
replyCount++;
break;
}
}
if (freeDepths)
xfree (depths);
}
*preply++ = replyCount;
/*
* Sort the lists by LBX server preference (increasing myIndices[] vals)
*/
for (i = 0; i <= replyCount - 2; i++)
for (j = replyCount - 1; j >= i; j--)
if (myIndices[j - 1] > myIndices[j])
{
char temp1 = myIndices[j - 1];
char temp2 = hisIndices[j - 1];
myIndices[j - 1] = myIndices[j];
myIndices[j] = temp1;
hisIndices[j - 1] = hisIndices[j];
hisIndices[j] = temp2;
if (pixmap)
{
unsigned temp3 = retFormats[j - 1];
int *temp4 = retDepths[j - 1];
retFormats[j - 1] = retFormats[j];
retFormats[j] = temp3;
retDepths[j - 1] = retDepths[j];
retDepths[j] = temp4;
}
}
/*
* For each method supported, return to the proxy an index into
* the list sent by the proxy, the opcode to be used for the method,
* the pixmap formats supported, and the list of depths supported.
*/
for (i = 0; i < replyCount; i++)
{
*preply++ = hisIndices[i];
if (pixmap)
{
int left;
*preply++ = LbxPixmapCompMethods[myIndices[i]].methodOpCode;
*preply++ = retFormats[i];
*preply++ = left = retDepths[i][0];
j = 1;
while (left > 0)
{
*preply++ = retDepths[i][j];
left--;
}
}
else
{
*preply++ = LbxBitmapCompMethods[myIndices[i]].methodOpCode;
}
}
if (pixmap)
{
pno->numPixmapCompMethods = replyCount;
pno->pixmapCompMethods = myIndices;
pno->pixmapCompDepths = retDepths;
}
else
{
pno->numBitmapCompMethods = replyCount;
pno->bitmapCompMethods = myIndices;
}
if (hisIndices)
xfree (hisIndices);
if (pixmap)
{
if (retFormats)
xfree (retFormats);
}
return (preply - preplyStart);
}
static int
LbxBitmapCompOpt (LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
return (LbxImageCompOpt (0 /* bitmap */, pno, popt, optlen, preply));
}
static int
LbxPixmapCompOpt (LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
return (LbxImageCompOpt (1 /* Pixmap */, pno, popt, optlen, preply));
}
LbxBitmapCompMethod *
LbxSrvrLookupBitmapCompMethod (LbxProxyPtr proxy,
int methodOpCode)
{
int i;
for (i = 0; i < proxy->numBitmapCompMethods; i++)
{
LbxBitmapCompMethod *method;
method = &LbxBitmapCompMethods[proxy->bitmapCompMethods[i]];
if (method->methodOpCode == methodOpCode)
return (method);
}
return (NULL);
}
LbxPixmapCompMethod *
LbxSrvrLookupPixmapCompMethod (LbxProxyPtr proxy,
int methodOpCode)
{
int i;
for (i = 0; i < proxy->numPixmapCompMethods; i++)
{
LbxPixmapCompMethod *method;
method = &LbxPixmapCompMethods[proxy->pixmapCompMethods[i]];
if (method->methodOpCode == methodOpCode)
return (method);
}
return (NULL);
}
LbxBitmapCompMethod *
LbxSrvrFindPreferredBitmapCompMethod (LbxProxyPtr proxy)
{
if (proxy->numBitmapCompMethods == 0)
return NULL;
else
return (&LbxBitmapCompMethods[proxy->bitmapCompMethods[0]]);
}
LbxPixmapCompMethod *
LbxSrvrFindPreferredPixmapCompMethod (LbxProxyPtr proxy,
int format,
int depth)
{
if (proxy->numPixmapCompMethods == 0)
return NULL;
else
{
LbxPixmapCompMethod *method;
int i, j;
for (i = 0; i < proxy->numPixmapCompMethods; i++)
{
method = &LbxPixmapCompMethods[proxy->pixmapCompMethods[i]];
if ((method->formatMask & (1 << format)))
{
int n = proxy->pixmapCompDepths[i][0];
j = 1;
while (n > 0)
{
if (depth == proxy->pixmapCompDepths[i][j])
return method;
else
n--;
}
}
}
return NULL;
}
}
static int
MergeDepths (int *depths,
LbxPixmapCompMethod *method)
{
int i, j, count;
int temp[LBX_MAX_DEPTHS + 1];
temp[0] = count = 0;
for (i = 1; i <= depths[0]; i++)
{
for (j = 0; j < method->depthCount; j++)
if (method->depths[j] == depths[i])
{
temp[0]++;
temp[++count] = depths[i];
break;
}
}
memcpy (depths, temp, (count + 1) * sizeof (int));
return (count);
}
#define LbxCmapAllMethod "XC-CMAP"
static int
LbxCmapAllOpt (LbxNegOptsPtr pno,
unsigned char *popt,
int optlen,
unsigned char *preply)
{
int numMethods = *popt++;
int i;
for (i = 0; i < numMethods; i++)
{
int len;
char *methodName;
len = *popt++;
methodName = (char *) popt;
popt += len;
if (!strncmp(methodName, LbxCmapAllMethod, len))
break;
}
if (i >= numMethods)
i = 0; /* assume first one is proxy's favorite */
*preply = i;
return 1;
}