diff options
Diffstat (limited to 'lbx/lbxopts.c')
-rw-r--r-- | lbx/lbxopts.c | 817 |
1 files changed, 817 insertions, 0 deletions
diff --git a/lbx/lbxopts.c b/lbx/lbxopts.c new file mode 100644 index 000000000..fe9af687e --- /dev/null +++ b/lbx/lbxopts.c @@ -0,0 +1,817 @@ +/* $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. + * + */ + +#ifdef OPTDEBUG +#include <stdio.h> +#endif +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "lbxserve.h" +#include "lbxstr.h" +#include "lbximage.h" +#include "lbxopts.h" +#include "lbxsrvopts.h" +#ifndef NO_ZLIB +#include "lbxzlib.h" +#endif /* NO_ZLIB */ + +static int LbxDeltaOpt(); +static int LbxProxyDeltaOpt(); +static int LbxServerDeltaOpt(); +static int LbxStreamCompOpt(); +static int LbxBitmapCompOpt(); +static int LbxPixmapCompOpt(); +static int LbxMessageCompOpt(); +static int LbxUseTagsOpt(); +static int LbxCmapAllOpt(); + +/* + * List of LBX options we recognize and are willing to negotiate + */ +static struct _LbxOptionParser { + CARD8 optcode; + int (*parser)(); +} 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 + */ +LbxOptionInit(pno) + 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(pno, popt, optlen, preply) + 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(pno, popt, optlen, preply) + LbxNegOptsPtr pno; + unsigned char *popt; + int optlen; + unsigned char *preply; +{ + return LbxDeltaOpt(popt, optlen, preply, + &pno->proxyDeltaN, &pno->proxyDeltaMaxLen); +} + +static int +LbxServerDeltaOpt(pno, popt, optlen, preply) + LbxNegOptsPtr pno; + unsigned char *popt; + int optlen; + unsigned char *preply; +{ + return LbxDeltaOpt(popt, optlen, preply, + &pno->serverDeltaN, &pno->serverDeltaMaxLen); +} + +static int +LbxDeltaOpt(popt, optlen, preply, pn, pmaxlen) + 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 int ZlibParse(); + +static struct _LbxStreamCompParser { + int typelen; + char *type; + int (*parser)(); +} 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(pno, popt, optlen, preply) + 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; +} + + +extern LbxStreamCompHandle ZlibInit(); +extern int ZlibStuffInput(), ZlibInputAvail(), ZlibFlush(), + ZlibRead(), ZlibWriteV(); +extern void ZlibCompressOn(), ZlibCompressOff(), ZlibFree(); + + +static int +ZlibParse(pno, popt, optlen, preply) + 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 = ZlibInit; + pno->streamOpts.streamCompArg = (pointer) 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 = ZlibFree; + + return (0); +} + +static int +LbxMessageCompOpt(pno, popt, optlen, preply) + 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(pno, popt, optlen, preply) + 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 MergeDepths (); + + +static int +LbxImageCompOpt (pixmap, pno, popt, optlen, preply) + +Bool pixmap; +LbxNegOptsPtr pno; +unsigned char *popt; +int optlen; +unsigned char *preply; + +{ + unsigned char *preplyStart = preply; + int numMethods = *popt++; + char *myIndices, *hisIndices; + unsigned *retFormats; + int **retDepths; + int replyCount = 0; + int status, i, j; + + if (numMethods == 0) + { + if (pixmap) + pno->numPixmapCompMethods = 0; + else + pno->numBitmapCompMethods = 0; + + *preply++ = 0; + return (1); + } + + myIndices = (char *) xalloc (numMethods); + hisIndices = (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 formatMask, newFormatMask; + int depthCount, *depths, 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 (pno, popt, optlen, preply) + +LbxNegOptsPtr pno; +unsigned char *popt; +int optlen; +unsigned char *preply; + +{ + return (LbxImageCompOpt (0 /* bitmap */, pno, popt, optlen, preply)); +} + + +static int +LbxPixmapCompOpt (pno, popt, optlen, preply) + +LbxNegOptsPtr pno; +unsigned char *popt; +int optlen; +unsigned char *preply; + +{ + return (LbxImageCompOpt (1 /* Pixmap */, pno, popt, optlen, preply)); +} + + +LbxBitmapCompMethod * +LbxSrvrLookupBitmapCompMethod (proxy, methodOpCode) + +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 (proxy, methodOpCode) + +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 (proxy) + +LbxProxyPtr proxy; + +{ + if (proxy->numBitmapCompMethods == 0) + return NULL; + else + return (&LbxBitmapCompMethods[proxy->bitmapCompMethods[0]]); +} + + + +LbxPixmapCompMethod * +LbxSrvrFindPreferredPixmapCompMethod (proxy, format, depth) + +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 (depths, method) + +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 (pno, popt, optlen, preply) + +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; +} |