summaryrefslogtreecommitdiff
path: root/lbx/lbxopts.c
diff options
context:
space:
mode:
Diffstat (limited to 'lbx/lbxopts.c')
-rw-r--r--lbx/lbxopts.c817
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;
+}