check_for_list_or_dict_or_blob_or_string_arg(typval_T *args, int idx)
{
    if (args[idx].v_type != VAR_LIST
	    && args[idx].v_type != VAR_DICT
	    && args[idx].v_type != VAR_BLOB
	    && args[idx].v_type != VAR_STRING)
    {
	semsg(_(e_list_dict_blob_or_string_required_for_argument_nr), idx + 1);
	return FAIL;
    }
    return OK;
}


check_for_unknown_arg(typval_T *args, int idx)
{
    if (args[idx].v_type != VAR_UNKNOWN)
    {
	semsg(_(e_too_many_arguments), idx + 1);
	return FAIL;
    }
    return OK;
}

patch 9.0.0104: going beyond allocated memory when evaluating string constant

Problem:    Going beyond allocated memory when evaluating string constant.
Solution:   Properly skip over <Key> form.


tv_get_string_buf_chk(typval_T *varp, char_u *buf)
{
    return tv_get_string_buf_chk_strict(varp, buf, FALSE);
}


typval_compare_null(typval_T *tv1, typval_T *tv2)
{
    if ((tv1->v_type == VAR_SPECIAL && tv1->vval.v_number == VVAL_NULL)
	    || (tv2->v_type == VAR_SPECIAL && tv2->vval.v_number == VVAL_NULL))
    {
	typval_T	*tv = tv1->v_type == VAR_SPECIAL ? tv2 : tv1;

	switch (tv->v_type)
	{
	    case VAR_BLOB: return tv->vval.v_blob == NULL;
#ifdef FEAT_JOB_CHANNEL
	    case VAR_CHANNEL: return tv->vval.v_channel == NULL;
#endif
	    case VAR_DICT: return tv->vval.v_dict == NULL;
	    case VAR_FUNC: return tv->vval.v_string == NULL;
#ifdef FEAT_JOB_CHANNEL
	    case VAR_JOB: return tv->vval.v_job == NULL;
#endif
	    case VAR_LIST: return tv->vval.v_list == NULL;
	    case VAR_PARTIAL: return tv->vval.v_partial == NULL;
	    case VAR_STRING: return tv->vval.v_string == NULL;

	    case VAR_NUMBER: if (!in_vim9script())
				 return tv->vval.v_number == 0;
			     break;
#ifdef FEAT_FLOAT
	    case VAR_FLOAT: if (!in_vim9script())
				 return tv->vval.v_float == 0.0;
			     break;
#endif
	    default: break;
	}
    }
    // although comparing null with number, float or bool is not very useful
    // we won't give an error
    return FALSE;
}


check_for_string_or_dict_arg(typval_T *args, int idx)
{
    if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_DICT)
    {
	semsg(_(e_string_or_dict_required_for_argument_nr), idx + 1);
	return FAIL;
    }
    return OK;
}


tv_get_buf(typval_T *tv, int curtab_only)
{
    char_u	*name = tv->vval.v_string;
    buf_T	*buf;

    if (tv->v_type == VAR_NUMBER)
	return buflist_findnr((int)tv->vval.v_number);
    if (tv->v_type != VAR_STRING)
	return NULL;
    if (name == NULL || *name == NUL)
	return curbuf;
    if (name[0] == '$' && name[1] == NUL)
	return lastbuf;

    buf = buflist_find_by_name(name, curtab_only);

    // If not found, try expanding the name, like done for bufexists().
    if (buf == NULL)
	buf = find_buffer(tv);

    return buf;
}


check_for_opt_bool_arg(typval_T *args, int idx)
{
    if (args[idx].v_type == VAR_UNKNOWN)
	return OK;
    return check_for_bool_arg(args, idx);
}


tv_get_lnum(typval_T *argvars)
{
    linenr_T	lnum = -1;

    if (argvars[0].v_type != VAR_STRING || !in_vim9script())
	lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
    if (lnum <= 0 && argvars[0].v_type != VAR_NUMBER)
    {
	int	fnum;
	pos_T	*fp;

	// no valid number, try using arg like line()
	fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
	if (fp != NULL)
	    lnum = fp->lnum;
    }
    return lnum;
}


check_for_list_or_dict_or_blob_arg(typval_T *args, int idx)
{
    if (args[idx].v_type != VAR_LIST
	    && args[idx].v_type != VAR_DICT
	    && args[idx].v_type != VAR_BLOB)
    {
	semsg(_(e_list_dict_or_blob_required_for_argument_nr), idx + 1);
	return FAIL;
    }
    return OK;
}


typval_compare_func(
	typval_T    *tv1,
	typval_T    *tv2,
	exprtype_T  type,
	int	    ic,
	int	    *res)
{
    int	    val = 0;

    if (type != EXPR_EQUAL && type != EXPR_NEQUAL
	    && type != EXPR_IS && type != EXPR_ISNOT)
    {
	emsg(_(e_invalid_operation_for_funcrefs));
	return FAIL;
    }
    if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL)
	    || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL))
	// When both partials are NULL, then they are equal.
	// Otherwise they are not equal.
	val = (tv1->vval.v_partial == tv2->vval.v_partial);
    else if (type == EXPR_IS || type == EXPR_ISNOT)
    {
	if (tv1->v_type == VAR_FUNC && tv2->v_type == VAR_FUNC)
	    // strings are considered the same if their value is
	    // the same
	    val = tv_equal(tv1, tv2, ic, FALSE);
	else if (tv1->v_type == VAR_PARTIAL && tv2->v_type == VAR_PARTIAL)
	    val = (tv1->vval.v_partial == tv2->vval.v_partial);
	else
	    val = FALSE;
    }
    else
	val = tv_equal(tv1, tv2, ic, FALSE);
    if (type == EXPR_NEQUAL || type == EXPR_ISNOT)
	val = !val;
    *res = val;
    return OK;
}


check_for_chan_or_job_arg(typval_T *args, int idx)
{
    if (args[idx].v_type != VAR_CHANNEL && args[idx].v_type != VAR_JOB)
    {
	semsg(_(e_chan_or_job_required_for_argument_nr), idx + 1);
	return FAIL;
    }
    return OK;
}


tv_get_string_chk(typval_T *varp)
{
    static char_u   mybuf[NUMBUFLEN];

    return tv_get_string_buf_chk(varp, mybuf);
}


init_tv(typval_T *varp)
{
    if (varp != NULL)
	CLEAR_POINTER(varp);
}


check_for_opt_list_arg(typval_T *args, int idx)
{
    return (args[idx].v_type == VAR_UNKNOWN
	    || check_for_list_arg(args, idx) != FAIL);
}


check_for_blob_arg(typval_T *args, int idx)
{
    if (args[idx].v_type != VAR_BLOB)
    {
	semsg(_(e_blob_required_for_argument_nr), idx + 1);
	return FAIL;
    }
    return OK;
}


check_for_list_arg(typval_T *args, int idx)
{
    if (args[idx].v_type != VAR_LIST)
    {
	    semsg(_(e_list_required_for_argument_nr), idx + 1);
	return FAIL;
    }
    return OK;
}


check_for_opt_string_or_number_arg(typval_T *args, int idx)
{
    return (args[idx].v_type == VAR_UNKNOWN
	    || check_for_string_or_number_arg(args, idx) != FAIL);
}


eval_lit_string(char_u **arg, typval_T *rettv, int evaluate, int interpolate)
{
    char_u	*p;
    char_u	*str;
    int		reduce = interpolate ? -1 : 0;
    int		off = interpolate ? 0 : 1;

    // Find the end of the string, skipping ''.
    for (p = *arg + off; *p != NUL; MB_PTR_ADV(p))
    {
	if (*p == '\'')
	{
	    if (p[1] != '\'')
		break;
	    ++reduce;
	    ++p;
	}
	else if (interpolate)
	{
	    if (*p == '{')
	    {
		if (p[1] != '{')
		    break;
		++p;
		++reduce;
	    }
	    else if (*p == '}')
	    {
		++p;
		if (*p != '}')
		{
		    semsg(_(e_stray_closing_curly_str), *arg);
		    return FAIL;
		}
		++reduce;
	    }
	}
    }

    if (*p != '\'' && !(interpolate && *p == '{'))
    {
	semsg(_(e_missing_single_quote_str), *arg);
	return FAIL;
    }

    // If only parsing return after setting "*arg"
    if (!evaluate)
    {
	*arg = p + off;
	return OK;
    }

    // Copy the string into allocated memory, handling '' to ' reduction and
    // any expressions.
    str = alloc((p - *arg) - reduce);
    if (str == NULL)
	return FAIL;
    rettv->v_type = VAR_STRING;
    rettv->vval.v_string = str;

    for (p = *arg + off; *p != NUL; )
    {
	if (*p == '\'')
	{
	    if (p[1] != '\'')
		break;
	    ++p;
	}
	else if (interpolate && (*p == '{' || *p == '}'))
	{
	    if (*p == '{' && p[1] != '{')
		break;
	    ++p;
	}
	MB_COPY_CHAR(p, str);
    }
    *str = NUL;
    *arg = p + off;

    return OK;
}


eval_number(
	char_u	    **arg,
	typval_T    *rettv,
	int	    evaluate,
	int	    want_string UNUSED)
{
    int		len;
    int		skip_quotes = !in_old_script(4);
#ifdef FEAT_FLOAT
    char_u	*p;
    int		get_float = FALSE;

    // We accept a float when the format matches
    // "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?".  This is very
    // strict to avoid backwards compatibility problems.
    // With script version 2 and later the leading digit can be
    // omitted.
    // Don't look for a float after the "." operator, so that
    // ":let vers = 1.2.3" doesn't fail.
    if (**arg == '.')
	p = *arg;
    else
    {
	p = *arg + 1;
	if (skip_quotes)
	    for (;;)
	    {
		if (*p == '\'')
		    ++p;
		if (!vim_isdigit(*p))
		    break;
		p = skipdigits(p);
	    }
	else
	    p = skipdigits(p);
    }
    if (!want_string && p[0] == '.' && vim_isdigit(p[1]))
    {
	get_float = TRUE;
	p = skipdigits(p + 2);
	if (*p == 'e' || *p == 'E')
	{
	    ++p;
	    if (*p == '-' || *p == '+')
		++p;
	    if (!vim_isdigit(*p))
		get_float = FALSE;
	    else
		p = skipdigits(p + 1);
	}
	if (ASCII_ISALPHA(*p) || *p == '.')
	    get_float = FALSE;
    }
    if (get_float)
    {
	float_T	f;

	*arg += string2float(*arg, &f, skip_quotes);
	if (evaluate)
	{
	    rettv->v_type = VAR_FLOAT;
	    rettv->vval.v_float = f;
	}
    }
    else
#endif
    if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z'))
    {
	char_u  *bp;
	blob_T  *blob = NULL;  // init for gcc

	// Blob constant: 0z0123456789abcdef
	if (evaluate)
	    blob = blob_alloc();
	for (bp = *arg + 2; vim_isxdigit(bp[0]); bp += 2)
	{
	    if (!vim_isxdigit(bp[1]))
	    {
		if (blob != NULL)
		{
		    emsg(_(e_blob_literal_should_have_an_even_number_of_hex_characters));
		    ga_clear(&blob->bv_ga);
		    VIM_CLEAR(blob);
		}
		return FAIL;
	    }
	    if (blob != NULL)
		ga_append(&blob->bv_ga,
			     (hex2nr(*bp) << 4) + hex2nr(*(bp+1)));
	    if (bp[2] == '.' && vim_isxdigit(bp[3]))
		++bp;
	}
	if (blob != NULL)
	    rettv_blob_set(rettv, blob);
	*arg = bp;
    }
    else
    {
	varnumber_T	n;

	// decimal, hex or octal number
	vim_str2nr(*arg, NULL, &len, skip_quotes
		      ? STR2NR_NO_OCT + STR2NR_QUOTE
		      : STR2NR_ALL, &n, NULL, 0, TRUE);
	if (len == 0)
	{
	    if (evaluate)
		semsg(_(e_invalid_expression_str), *arg);
	    return FAIL;
	}
	*arg += len;
	if (evaluate)
	{
	    rettv->v_type = VAR_NUMBER;
	    rettv->vval.v_number = n;
	}
    }
    return OK;
}


check_for_opt_chan_or_job_arg(typval_T *args, int idx)
{
    return (args[idx].v_type == VAR_UNKNOWN
	    || check_for_chan_or_job_arg(args, idx) != FAIL);
}


size_t get_default_max_mem_usage(void)
{
	size_t total_mem_size = jas_get_total_mem_size();
	size_t max_mem;
	if (total_mem_size) {
		max_mem = 0.90 * total_mem_size;
	} else {
		max_mem = JAS_DEFAULT_MAX_MEM_USAGE;
	}
	return max_mem;
}

fix memory leaks in function cmdopts_parse


int addopt(char *optstr, int maxlen, const char *s)
{
	size_t n;
	size_t m;

	n = strlen(optstr);
	m = n + strlen(s) + 1;
	if (m > JAS_CAST(size_t, maxlen)) {
		return 1;
	}
	if (n > 0) {
		strcat(optstr, "\n");
	}
	strcat(optstr, s);
	return 0;
}


void cmdusage()
{
	const char *s;
	int i;
	cmdinfo();
	fprintf(stderr, "usage: %s [options]\n", cmdname);
	for (i = 0, s = helpinfo[i]; s; ++i, s = helpinfo[i]) {
		fprintf(stderr, "%s", s);
	}

	fprintf(stderr, "The following formats are supported:\n");
	int fmtind;
	const jas_image_fmtinfo_t *fmtinfo;
	int numfmts = jas_image_getnumfmts();
	for (fmtind = 0; fmtind < numfmts; ++fmtind) {
		if (!(fmtinfo = jas_image_getfmtbyind(fmtind))) {
			break;
		}
		fprintf(stderr, "    %s %-5s    %s\n",
		  fmtinfo->enabled ? "[enabled] " : "[disabled]",
		  fmtinfo->name,
		  fmtinfo->desc);
	}
	exit(EXIT_FAILURE);
}


jas_image_t *converttosrgb(jas_image_t *inimage)
{
	jas_image_t *outimage;
	jas_cmpixmap_t inpixmap;
	jas_cmpixmap_t outpixmap;
	jas_cmcmptfmt_t incmptfmts[16];
	jas_cmcmptfmt_t outcmptfmts[16];

	outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB);
	assert(outprof);
	xform = jas_cmxform_create(jas_image_cmprof(inimage), outprof, 0, JAS_CMXFORM_FWD, JAS_CMXFORM_INTENT_PER, JAS_CMXFORM_OPTM_SPEED);
	assert(xform);

	inpixmap.numcmpts = jas_image_numcmpts(oldimage);
	outpixmap.numcmpts = 3;
	for (i = 0; i < inpixmap.numcmpts; ++i) {
		inpixmap.cmptfmts[i] = &incmptfmts[i];
	}
	for (i = 0; i < outpixmap.numcmpts; ++i)
		outpixmap.cmptfmts[i] = &outcmptfmts[i];
	if (jas_cmxform_apply(xform, &inpixmap, &outpixmap))
		abort();

	jas_xform_destroy(xform);
	jas_cmprof_destroy(outprof);
	return 0;
}


void cleanup(void)
{
#if defined(JAS_USE_JAS_INIT)
	jas_cleanup();
#else
	jas_cleanup_thread();
	jas_cleanup_library();
#endif
}


cmdopts_t *cmdopts_parse(int argc, char **argv)
{
	enum {
		CMDOPT_HELP = 0,
		CMDOPT_VERBOSE,
		CMDOPT_QUIET,
		CMDOPT_INFILE,
		CMDOPT_INFMT,
		CMDOPT_INOPT,
		CMDOPT_OUTFILE,
		CMDOPT_OUTFMT,
		CMDOPT_OUTOPT,
		CMDOPT_VERSION,
		CMDOPT_DEBUG,
		CMDOPT_CMPTNO,
		CMDOPT_SRGB,
		CMDOPT_MAXMEM,
		CMDOPT_LIST_ENABLED_CODECS,
		CMDOPT_LIST_ALL_CODECS,
		CMDOPT_ENABLE_FORMAT,
		CMDOPT_ENABLE_ALL_FORMATS,
	};

	static const jas_opt_t cmdoptions[] = {
		{CMDOPT_HELP, "help", 0},
		{CMDOPT_VERBOSE, "verbose", 0},
		{CMDOPT_QUIET, "quiet", 0},
		{CMDOPT_QUIET, "q", 0},
		{CMDOPT_INFILE, "input", JAS_OPT_HASARG},
		{CMDOPT_INFILE, "f", JAS_OPT_HASARG},
		{CMDOPT_INFMT, "input-format", JAS_OPT_HASARG},
		{CMDOPT_INFMT, "t", JAS_OPT_HASARG},
		{CMDOPT_INOPT, "input-option", JAS_OPT_HASARG},
		{CMDOPT_INOPT, "o", JAS_OPT_HASARG},
		{CMDOPT_OUTFILE, "output", JAS_OPT_HASARG},
		{CMDOPT_OUTFILE, "F", JAS_OPT_HASARG},
		{CMDOPT_OUTFMT, "output-format", JAS_OPT_HASARG},
		{CMDOPT_OUTFMT, "T", JAS_OPT_HASARG},
		{CMDOPT_OUTOPT, "output-option", JAS_OPT_HASARG},
		{CMDOPT_OUTOPT, "O", JAS_OPT_HASARG},
		{CMDOPT_VERSION, "version", 0},
		{CMDOPT_DEBUG, "debug-level", JAS_OPT_HASARG},
		{CMDOPT_CMPTNO, "cmptno", JAS_OPT_HASARG},
		{CMDOPT_SRGB, "force-srgb", 0},
		{CMDOPT_SRGB, "S", 0},
		{CMDOPT_MAXMEM, "memory-limit", JAS_OPT_HASARG},
		{CMDOPT_LIST_ENABLED_CODECS, "list-enabled-formats", 0},
		{CMDOPT_LIST_ALL_CODECS, "list-all-formats", 0},
		{CMDOPT_ENABLE_FORMAT, "enable-format", JAS_OPT_HASARG},
		{CMDOPT_ENABLE_ALL_FORMATS, "enable-all-formats", 0},
		{-1, 0, 0}
	};

	cmdopts_t *cmdopts;
	int c;

	if (!(cmdopts = malloc(sizeof(cmdopts_t)))) {
		fprintf(stderr, "error: insufficient memory\n");
		exit(EXIT_FAILURE);
	}

	cmdopts->infile = 0;
	cmdopts->infmt = -1;
	cmdopts->infmt_str = 0;
	cmdopts->inopts = 0;
	cmdopts->inoptsbuf[0] = '\0';
	cmdopts->outfile = 0;
	cmdopts->outfmt = -1;
	cmdopts->outfmt_str = 0;
	cmdopts->outopts = 0;
	cmdopts->outoptsbuf[0] = '\0';
	cmdopts->verbose = 0;
	cmdopts->version = 0;
	cmdopts->cmptno = -1;
	cmdopts->debug = 0;
	cmdopts->srgb = 0;
	cmdopts->list_codecs = 0;
	cmdopts->list_codecs_all = 0;
	cmdopts->help = 0;
	cmdopts->max_mem = get_default_max_mem_usage();
	cmdopts->enable_format = 0;
	cmdopts->enable_all_formats = 0;

	while ((c = jas_getopt(argc, argv, cmdoptions)) != EOF) {
		switch (c) {
		case CMDOPT_HELP:
			cmdopts->help = 1;
			break;
		case CMDOPT_VERBOSE:
			cmdopts->verbose = 1;
			break;
		case CMDOPT_QUIET:
			cmdopts->verbose = -1;
			break;
		case CMDOPT_VERSION:
			cmdopts->version = 1;
			break;
		case CMDOPT_LIST_ENABLED_CODECS:
			cmdopts->list_codecs = 1;
			cmdopts->list_codecs_all = 0;
			break;
		case CMDOPT_LIST_ALL_CODECS:
			cmdopts->list_codecs = 1;
			cmdopts->list_codecs_all = 1;
			break;
		case CMDOPT_DEBUG:
			cmdopts->debug = atoi(jas_optarg);
			break;
		case CMDOPT_INFILE:
			cmdopts->infile = jas_optarg;
			break;
		case CMDOPT_INFMT:
			cmdopts->infmt_str= jas_optarg;
			break;
		case CMDOPT_INOPT:
			addopt(cmdopts->inoptsbuf, OPTSMAX, jas_optarg);
			cmdopts->inopts = cmdopts->inoptsbuf;
			break;
		case CMDOPT_OUTFILE:
			cmdopts->outfile = jas_optarg;
			break;
		case CMDOPT_OUTFMT:
			cmdopts->outfmt_str = jas_optarg;
			break;
		case CMDOPT_OUTOPT:
			addopt(cmdopts->outoptsbuf, OPTSMAX, jas_optarg);
			cmdopts->outopts = cmdopts->outoptsbuf;
			break;
		case CMDOPT_CMPTNO:
			cmdopts->cmptno = atoi(jas_optarg);
			break;
		case CMDOPT_SRGB:
			cmdopts->srgb = 1;
			break;
		case CMDOPT_MAXMEM:
			cmdopts->max_mem = strtoull(jas_optarg, 0, 10);
			break;
		case CMDOPT_ENABLE_FORMAT:
			cmdopts->enable_format = jas_optarg;
			break;
		case CMDOPT_ENABLE_ALL_FORMATS:
			cmdopts->enable_all_formats = 1;
			break;
		default:
			cmdopts_destroy(cmdopts);
			badusage();
			break;
		}
	}

	while (jas_optind < argc) {
		fprintf(stderr,
		  "warning: ignoring bogus command line argument %s\n",
		  argv[jas_optind]);
		++jas_optind;
	}

	if (cmdopts->version || cmdopts->list_codecs || cmdopts->help) {
		goto done;
	}

	if (!cmdopts->outfmt_str && !cmdopts->outfile) {
		fprintf(stderr, "error: cannot determine output format\n");
		cmdopts_destroy(cmdopts);
		badusage();
	}

done:
	return cmdopts;
}


int main(int argc, char **argv)
{
	jas_image_t *image;
	cmdopts_t *cmdopts;
	jas_stream_t *in;
	jas_stream_t *out;
	jas_tmr_t dectmr;
	jas_tmr_t enctmr;
	double dectime;
	double enctime;
	int_fast16_t numcmpts;
	int i;

	/* Determine the base name of this command. */
	if ((cmdname = strrchr(argv[0], '/'))) {
		++cmdname;
	} else {
		cmdname = argv[0];
	}

	/* Parse the command line options. */
	if (!(cmdopts = cmdopts_parse(argc, argv))) {
		fprintf(stderr, "error: cannot parse command line\n");
		exit(EXIT_FAILURE);
	}

	if (cmdopts->version) {
		printf("%s\n", JAS_VERSION);
		fprintf(stderr, "libjasper %s\n", jas_getversion());
		exit(EXIT_SUCCESS);
	}

#if defined(JAS_USE_JAS_INIT)
	if (jas_init()) {
		fprintf(stderr, "cannot initialize JasPer library\n");
		exit(EXIT_FAILURE);
	}
	jas_set_max_mem_usage(cmdopts->max_mem);
	jas_setdbglevel(cmdopts->debug);
	atexit(cleanup);
#else
	jas_conf_clear();
	static jas_std_allocator_t allocator;
	jas_std_allocator_init(&allocator);
	jas_conf_set_allocator(&allocator.base);
	jas_conf_set_debug_level(cmdopts->debug);
	jas_conf_set_max_mem_usage(cmdopts->max_mem);
	if (cmdopts->verbose < 0) {
		jas_conf_set_vlogmsgf(jas_vlogmsgf_discard);
	}
	if (jas_init_library()) {
		fprintf(stderr, "cannot initialize JasPer library\n");
		exit(EXIT_FAILURE);
	}
	if (jas_init_thread()) {
		fprintf(stderr, "cannot initialize thread\n");
		exit(EXIT_FAILURE);
	}
	atexit(cleanup);
#endif

	if (cmdopts->enable_all_formats || cmdopts->enable_format) {
		for (i = 0; i < jas_image_getnumfmts(); ++i) {
			const jas_image_fmtinfo_t *fmtinfo = jas_image_getfmtbyind(i);
			if (cmdopts->enable_all_formats || !strcmp(fmtinfo->name,
			  cmdopts->enable_format)) {
				jas_image_setfmtenable(i, 1);
			}
		}
	}

	if (cmdopts->help) {
		cmdusage();
	}

	if (cmdopts->list_codecs) {
		size_t num_formats = jas_image_getnumfmts();
		for (i = 0; i < num_formats; ++i) {
			const jas_image_fmtinfo_t *fmt;
			fmt = jas_image_getfmtbyind(i);
			if (cmdopts->list_codecs_all || fmt->enabled) {
				printf("%s\n", fmt->name);
			}
		}
		exit(EXIT_SUCCESS);
	}

	if (cmdopts->infmt_str) {
		if ((cmdopts->infmt = jas_image_strtofmt(cmdopts->infmt_str)) < 0) {
			fprintf(stderr, "warning: ignoring invalid input format %s\n",
			  cmdopts->infmt_str);
			cmdopts->infmt = -1;
		}
	} else {
		cmdopts->infmt = -1;
	}
	if (cmdopts->outfmt_str) {
		if ((cmdopts->outfmt = jas_image_strtofmt(cmdopts->outfmt_str)) < 0) {
			fprintf(stderr, "error: invalid output format %s\n",
			cmdopts->outfmt_str);
			exit(EXIT_FAILURE);
		}
	} else {
		if (cmdopts->outfmt < 0 && cmdopts->outfile) {
			if ((cmdopts->outfmt = jas_image_fmtfromname(cmdopts->outfile)) <
			  0) {
				cmdopts->outfmt = -1;
			}
		}
	}
	if (cmdopts->outfmt < 0) {
		fprintf(stderr, "error: cannot determine output image format\n");
		exit(EXIT_FAILURE);
	}

	if (cmdopts->verbose > 0) {
		cmdinfo();
	}

	/* Open the input image file. */
	if (cmdopts->infile) {
		/* The input image is to be read from a file. */
		if (!(in = jas_stream_fopen(cmdopts->infile, "rb"))) {
			fprintf(stderr, "error: cannot open input image file %s\n",
			  cmdopts->infile);
			exit(EXIT_FAILURE);
		}
	} else {
		/* The input image is to be read from standard input. */
		if (!(in = jas_stream_fdopen(0, "rb"))) {
			fprintf(stderr, "error: cannot open standard input\n");
			exit(EXIT_FAILURE);
		}
	}

	/* Open the output image file. */
	if (cmdopts->outfile) {
		/* The output image is to be written to a file. */
		if (!(out = jas_stream_fopen(cmdopts->outfile, "w+b"))) {
			fprintf(stderr, "error: cannot open output image file %s\n",
			  cmdopts->outfile);
			exit(EXIT_FAILURE);
		}
	} else {
		/* The output image is to be written to standard output. */
		if (!(out = jas_stream_fdopen(1, "w+b"))) {
			fprintf(stderr, "error: cannot open standard output\n");
			exit(EXIT_FAILURE);
		}
	}

	if (cmdopts->infmt < 0) {
		if ((cmdopts->infmt = jas_image_getfmt(in)) < 0) {
			fprintf(stderr, "error: input image has unknown format\n");
			exit(EXIT_FAILURE);
		}
	}

	/* Get the input image data. */
	jas_tmr_start(&dectmr);
	if (!(image = jas_image_decode(in, cmdopts->infmt, cmdopts->inopts))) {
		fprintf(stderr, "error: cannot load image data\n");
		exit(EXIT_FAILURE);
	}
	jas_tmr_stop(&dectmr);
	dectime = jas_tmr_get(&dectmr);

	/* If requested, throw away all of the components except one.
	  Why might this be desirable?  It is a hack, really.
	  None of the image formats other than the JPEG-2000 ones support
	  images with two, four, five, or more components.  This hack
	  allows such images to be decoded with the non-JPEG-2000 decoders,
	  one component at a time. */
	numcmpts = jas_image_numcmpts(image);
	if (cmdopts->cmptno >= 0 && cmdopts->cmptno < numcmpts) {
		for (i = numcmpts - 1; i >= 0; --i) {
			if (i != cmdopts->cmptno) {
				jas_image_delcmpt(image, i);
			}
		}
	}

	if (cmdopts->srgb) {
		jas_image_t *newimage;
		jas_cmprof_t *outprof;
		if (cmdopts->verbose >= 1) {
			fprintf(stderr, "forcing conversion to sRGB\n");
		}
		if (!(outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB))) {
			fprintf(stderr, "cannot create sRGB profile\n");
			exit(EXIT_FAILURE);
		}
		if (!(newimage = jas_image_chclrspc(image, outprof,
		  JAS_CMXFORM_INTENT_PER))) {
			fprintf(stderr, "cannot convert to sRGB\n");
			exit(EXIT_FAILURE);
		}
		jas_image_destroy(image);
		jas_cmprof_destroy(outprof);
		image = newimage;
	}

	/* Generate the output image data. */
	jas_tmr_start(&enctmr);
	if (jas_image_encode(image, out, cmdopts->outfmt, cmdopts->outopts)) {
		fprintf(stderr, "error: cannot encode image\n");
		exit(EXIT_FAILURE);
	}
	jas_stream_flush(out);
	jas_tmr_stop(&enctmr);
	enctime = jas_tmr_get(&enctmr);

	if (cmdopts->verbose > 0) {
		fprintf(stderr, "decoding time = %f\n", dectime);
		fprintf(stderr, "encoding time = %f\n", enctime);
	}

	/* If this fails, we don't care. */
	(void) jas_stream_close(in);

	/* Close the output image stream. */
	if (jas_stream_close(out)) {
		fprintf(stderr, "error: cannot close output image file\n");
		exit(EXIT_FAILURE);
	}

	cmdopts_destroy(cmdopts);
	jas_image_destroy(image);

	/* Success at last! :-) */
	return EXIT_SUCCESS;
}


SetKeyExplicit(XkbSrvInfoPtr xkbi,xkbSetMapReq *req,CARD8 *wire,
							XkbChangesPtr changes)
{
register unsigned	i,first,last;
XkbServerMapPtr		xkb = xkbi->desc->server;
CARD8 *			start;

    start= wire;
    first= req->firstKeyExplicit;
    last=  req->firstKeyExplicit+req->nKeyExplicit-1;
    bzero(&xkb->explicit[first],req->nKeyExplicit);
    for (i=0;i<req->totalKeyExplicit;i++,wire+= 2) {
	xkb->explicit[wire[0]]= wire[1];
    }
    if (first>0) {
	if (changes->map.changed&XkbExplicitComponentsMask) {
	    int oldLast;
	    oldLast= changes->map.first_key_explicit+
					changes->map.num_key_explicit-1;
	    if (changes->map.first_key_explicit<first)
		first= changes->map.first_key_explicit;
	    if (oldLast>last)
		last= oldLast;
	}
	changes->map.first_key_explicit= first;
	changes->map.num_key_explicit= (last-first)+1;
    }
    wire+= XkbPaddedSize(wire-start)-(wire-start);
    return (char *)wire;
}

xkb: ProcXkbSetDeviceInfo should work on all attached SDs.

If called with XkbUseCoreKbd, run through all attached SDs and replicate the
call. This way, we keep the SDs in sync with the MD as long as core clients
control the MDs.


_CheckSetDoodad(	char **		wire_inout,
			XkbGeometryPtr	geom,
			XkbSectionPtr	section,
			ClientPtr	client)
{
char *			wire;
xkbDoodadWireDesc *	dWire;
XkbDoodadPtr		doodad;

    dWire= (xkbDoodadWireDesc *)(*wire_inout);
    wire= (char *)&dWire[1];
    if (client->swapped) {
	register int n;
	swapl(&dWire->any.name,n);
	swaps(&dWire->any.top,n);
	swaps(&dWire->any.left,n);
	swaps(&dWire->any.angle,n);
    }
    CHK_ATOM_ONLY(dWire->any.name);
    doodad= XkbAddGeomDoodad(geom,section,dWire->any.name);
    if (!doodad)
	return BadAlloc;
    doodad->any.type= dWire->any.type;
    doodad->any.priority= dWire->any.priority;
    doodad->any.top= dWire->any.top;
    doodad->any.left= dWire->any.left;
    doodad->any.angle= dWire->any.angle;
    switch (doodad->any.type) {
	case XkbOutlineDoodad:
	case XkbSolidDoodad:
	    if (dWire->shape.colorNdx>=geom->num_colors) {
		client->errorValue= _XkbErrCode3(0x40,geom->num_colors,
							dWire->shape.colorNdx);
		return BadMatch;
	    }
	    if (dWire->shape.shapeNdx>=geom->num_shapes) {
		client->errorValue= _XkbErrCode3(0x41,geom->num_shapes,
							dWire->shape.shapeNdx);
		return BadMatch;
	    }
	    doodad->shape.color_ndx= dWire->shape.colorNdx;
	    doodad->shape.shape_ndx= dWire->shape.shapeNdx;
	    break;
	case XkbTextDoodad:
	    if (dWire->text.colorNdx>=geom->num_colors) {
		client->errorValue= _XkbErrCode3(0x42,geom->num_colors,
							dWire->text.colorNdx);
		return BadMatch;
	    }
	    if (client->swapped) {
		register int n;
		swaps(&dWire->text.width,n);
		swaps(&dWire->text.height,n);
	    }
	    doodad->text.width= dWire->text.width;
	    doodad->text.height= dWire->text.height;
	    doodad->text.color_ndx= dWire->text.colorNdx;
	    doodad->text.text= _GetCountedString(&wire,client->swapped);
	    doodad->text.font= _GetCountedString(&wire,client->swapped);
	    break;
	case XkbIndicatorDoodad:
	    if (dWire->indicator.onColorNdx>=geom->num_colors) {
		client->errorValue= _XkbErrCode3(0x43,geom->num_colors,
						dWire->indicator.onColorNdx);
		return BadMatch;
	    }
	    if (dWire->indicator.offColorNdx>=geom->num_colors) {
		client->errorValue= _XkbErrCode3(0x44,geom->num_colors,
						dWire->indicator.offColorNdx);
		return BadMatch;
	    }
	    if (dWire->indicator.shapeNdx>=geom->num_shapes) {
		client->errorValue= _XkbErrCode3(0x45,geom->num_shapes,
						dWire->indicator.shapeNdx);
		return BadMatch;
	    }
	    doodad->indicator.shape_ndx= dWire->indicator.shapeNdx;
	    doodad->indicator.on_color_ndx= dWire->indicator.onColorNdx;
	    doodad->indicator.off_color_ndx= dWire->indicator.offColorNdx;
	    break;
	case XkbLogoDoodad:
	    if (dWire->logo.colorNdx>=geom->num_colors) {
		client->errorValue= _XkbErrCode3(0x46,geom->num_colors,
							dWire->logo.colorNdx);
		return BadMatch;
	    }
	    if (dWire->logo.shapeNdx>=geom->num_shapes) {
		client->errorValue= _XkbErrCode3(0x47,geom->num_shapes,
							dWire->logo.shapeNdx);
		return BadMatch;
	    }
	    doodad->logo.color_ndx= dWire->logo.colorNdx;
	    doodad->logo.shape_ndx= dWire->logo.shapeNdx;
	    doodad->logo.logo_name= _GetCountedString(&wire,client->swapped);
	    break;
	default:
	    client->errorValue= _XkbErrCode2(0x4F,dWire->any.type);
	    return BadValue;
    }
    *wire_inout= wire;
    return Success;
}


CheckKeyBehaviors(	XkbDescPtr 		xkb,
			xkbSetMapReq *		req,
			xkbBehaviorWireDesc **	wireRtrn,
			int *			errorRtrn)
{
register xkbBehaviorWireDesc *	wire = *wireRtrn;
register XkbServerMapPtr	server = xkb->server;
register unsigned	 	i;
unsigned			first,last;

    if (((req->present&XkbKeyBehaviorsMask)==0)||(req->nKeyBehaviors<1)) {
	req->present&= ~XkbKeyBehaviorsMask;
	req->nKeyBehaviors= 0;
	return 1;
    }
    first= req->firstKeyBehavior;
    last=  req->firstKeyBehavior+req->nKeyBehaviors-1;
    if (first<req->minKeyCode) {
	*errorRtrn = _XkbErrCode3(0x31,first,req->minKeyCode);
	return 0;
    }
    if (last>req->maxKeyCode) {
	*errorRtrn = _XkbErrCode3(0x32,last,req->maxKeyCode);
	return 0;
    }

    for (i=0;i<req->totalKeyBehaviors;i++,wire++) {
	if ((wire->key<first)||(wire->key>last)) {
	    *errorRtrn = _XkbErrCode4(0x33,first,last,wire->key);
	    return 0;
	}
	if ((wire->type&XkbKB_Permanent)&&
	    ((server->behaviors[wire->key].type!=wire->type)||
	     (server->behaviors[wire->key].data!=wire->data))) {
	    *errorRtrn = _XkbErrCode3(0x33,wire->key,wire->type);
	    return 0;
	}
	if ((wire->type==XkbKB_RadioGroup)&&
		((wire->data&(~XkbKB_RGAllowNone))>XkbMaxRadioGroups)) {
	    *errorRtrn= _XkbErrCode4(0x34,wire->key,wire->data,
							XkbMaxRadioGroups);
	    return 0;
	}
	if ((wire->type==XkbKB_Overlay1)||(wire->type==XkbKB_Overlay2)) {
	    CHK_KEY_RANGE2(0x35,wire->key,1,xkb,*errorRtrn,0);
	}
    }
    *wireRtrn = wire;
    return 1;
}


SetVirtualMods(XkbSrvInfoPtr xkbi,xkbSetMapReq *req,CARD8 *wire,
						XkbChangesPtr changes)
{
register int 		i,bit,nMods;
XkbServerMapPtr		srv = xkbi->desc->server;

    if (((req->present&XkbVirtualModsMask)==0)||(req->virtualMods==0))
	return (char *)wire;
    for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
	if (req->virtualMods&bit) {
	    if (srv->vmods[i]!=wire[nMods]) {
		changes->map.changed|= XkbVirtualModsMask;
		changes->map.vmods|= bit;
		srv->vmods[i]= wire[nMods];
	    }
	    nMods++;
	}
    }
    return (char *)(wire+XkbPaddedSize(nMods));
}


_XkbCountAtoms(Atom *atoms,int maxAtoms,int *count)
{
register unsigned int i,bit,nAtoms;
register CARD32 atomsPresent;

    for (i=nAtoms=atomsPresent=0,bit=1;i<maxAtoms;i++,bit<<=1) {
	if (atoms[i]!=None) {
	    atomsPresent|= bit;
	    nAtoms++;
	}
    }
    if (count)
	*count= nAtoms;
    return atomsPresent;
}


XkbWriteKeyBehaviors(XkbDescPtr xkb,xkbGetMapReply *rep,char *buf,
							ClientPtr client)
{
    unsigned		i;
    xkbBehaviorWireDesc	*wire;
    XkbBehavior		*pBhvr;

    wire = (xkbBehaviorWireDesc *)buf;
    pBhvr= &xkb->server->behaviors[rep->firstKeyBehavior];
    for (i=0;i<rep->nKeyBehaviors;i++,pBhvr++) {
	if (pBhvr->type!=XkbKB_Default) {
	    wire->key=  i+rep->firstKeyBehavior;
	    wire->type= pBhvr->type;
	    wire->data= pBhvr->data;
	    wire++;
	}
    }
    buf = (char *)wire;
    return buf;
}


SetKeyActions(	XkbDescPtr	xkb,
		xkbSetMapReq *	req,
		CARD8 *		wire,
		XkbChangesPtr	changes)
{
register unsigned	i,first,last;
CARD8 *			nActs = wire;
XkbAction *		newActs;

    wire+= XkbPaddedSize(req->nKeyActs);
    for (i=0;i<req->nKeyActs;i++) {
	if (nActs[i]==0)
	    xkb->server->key_acts[i+req->firstKeyAct]= 0;
	else {
	    newActs= XkbResizeKeyActions(xkb,i+req->firstKeyAct,nActs[i]);
	    memcpy((char *)newActs,(char *)wire,
					nActs[i]*SIZEOF(xkbActionWireDesc));
	    wire+= nActs[i]*SIZEOF(xkbActionWireDesc);
	}
    }
    first= req->firstKeyAct;
    last= (first+req->nKeyActs-1);
    if (changes->map.changed&XkbKeyActionsMask) {
	int oldLast;
	oldLast= changes->map.first_key_act+changes->map.num_key_acts-1;
	if (changes->map.first_key_act<first)
	    first= changes->map.first_key_act;
	if (oldLast>last)
	    last= oldLast;
    }
    changes->map.changed|= XkbKeyActionsMask;
    changes->map.first_key_act= first;
    changes->map.num_key_acts= (last-first+1);
    return (char *)wire;
}


GetComponentSpec(unsigned char **pWire,Bool allowExpr,int *errRtrn)
{
int		len;
register int	i;
unsigned char	*wire,*str,*tmp,*legal;

    if (allowExpr)	legal= &componentExprLegal[0];
    else		legal= &componentSpecLegal[0];

    wire= *pWire;
    len= (*(unsigned char *)wire++);
    if (len>0) {
	str= (unsigned char *)_XkbCalloc(1, len+1);
	if (str) {
	    tmp= str;
	    for (i=0;i<len;i++) {
		if (legal[(*wire)/8]&(1<<((*wire)%8)))
		    *tmp++= *wire++;
		else wire++;
	    }
	    if (tmp!=str)
		*tmp++= '\0';
	    else {
		_XkbFree(str);
		str= NULL;
	    }
	}
	else {
	    *errRtrn= BadAlloc;
	}
    }
    else {
	str= NULL;
    }
    *pWire= wire;
    return (char *)str;
}


_XkbCopyMaskedAtoms(	Atom	*wire,
    			Atom	*dest,
			int   	 nAtoms,
			CARD32	 present)
{
register int i,bit;

    for (i=0,bit=1;(i<nAtoms)&&(present);i++,bit<<=1) {
	if ((present&bit)==0)
	    continue;
	dest[i]= *wire++;
    }
    return wire;
}


ProcXkbPerClientFlags(ClientPtr client)
{
    DeviceIntPtr 		dev;
    xkbPerClientFlagsReply 	rep;
    XkbInterestPtr		interest;
    Mask access_mode = DixGetAttrAccess | DixSetAttrAccess;

    REQUEST(xkbPerClientFlagsReq);
    REQUEST_SIZE_MATCH(xkbPerClientFlagsReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode);
    CHK_MASK_LEGAL(0x01,stuff->change,XkbPCF_AllFlagsMask);
    CHK_MASK_MATCH(0x02,stuff->change,stuff->value);

    interest = XkbFindClientResource((DevicePtr)dev,client);
    rep.type= X_Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    if (stuff->change) {
	client->xkbClientFlags&= ~stuff->change;
	client->xkbClientFlags|= stuff->value;
    }
    if (stuff->change&XkbPCF_AutoResetControlsMask) {
	Bool	want;
	want= stuff->value&XkbPCF_AutoResetControlsMask;
	if (interest && !want) {
	    interest->autoCtrls= interest->autoCtrlValues= 0;
	}
	else if (want && (!interest)) {
	    XID id = FakeClientID(client->index);
	    AddResource(id,RT_XKBCLIENT,dev);
	    interest= XkbAddClientResource((DevicePtr)dev,client,id);
	    if (!interest)
		return BadAlloc;
	}
	if (interest && want ) {
	    register unsigned affect;
	    affect= stuff->ctrlsToChange;

	    CHK_MASK_LEGAL(0x03,affect,XkbAllBooleanCtrlsMask);
	    CHK_MASK_MATCH(0x04,affect,stuff->autoCtrls);
	    CHK_MASK_MATCH(0x05,stuff->autoCtrls,stuff->autoCtrlValues);

	    interest->autoCtrls&= ~affect;
	    interest->autoCtrlValues&= ~affect;
	    interest->autoCtrls|= stuff->autoCtrls&affect;
	    interest->autoCtrlValues|= stuff->autoCtrlValues&affect;
	}
    }
    rep.supported = XkbPCF_AllFlagsMask;
    rep.value= client->xkbClientFlags&XkbPCF_AllFlagsMask;
    if (interest) {
	rep.autoCtrls= interest->autoCtrls;
	rep.autoCtrlValues= interest->autoCtrlValues;
    }
    else {
	rep.autoCtrls= rep.autoCtrlValues= 0;
    }
    if ( client->swapped ) {
	register int n;
	swaps(&rep.sequenceNumber, n);
	swapl(&rep.supported,n);
	swapl(&rep.value,n);
	swapl(&rep.autoCtrls,n);
	swapl(&rep.autoCtrlValues,n);
    }
    WriteToClient(client,SIZEOF(xkbPerClientFlagsReply), (char *)&rep);
    return client->noClientException;
}


XkbWriteGeomKeyAliases(char *wire,XkbGeometryPtr geom,Bool swap)
{
register int sz;

    sz= geom->num_key_aliases*(XkbKeyNameLength*2);
    if (sz>0) {
	memcpy(wire,(char *)geom->key_aliases,sz);
	wire+= sz;
    }
    return wire;
}


ProcXkbGetGeometry(ClientPtr client)
{
    DeviceIntPtr 	dev;
    xkbGetGeometryReply rep;
    XkbGeometryPtr	geom;
    Bool		shouldFree;
    Status		status;

    REQUEST(xkbGetGeometryReq);
    REQUEST_SIZE_MATCH(xkbGetGeometryReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
    CHK_ATOM_OR_NONE(stuff->name);

    geom= XkbLookupNamedGeometry(dev,stuff->name,&shouldFree);
    rep.type= X_Reply;
    rep.deviceID= dev->id;
    rep.sequenceNumber= client->sequence;
    rep.length= 0;
    status= XkbComputeGetGeometryReplySize(geom,&rep,stuff->name);
    if (status!=Success)
	 return status;
    else return XkbSendGeometry(client,geom,&rep,shouldFree);
}


XkbSizeGeomSections(XkbGeometryPtr geom)
{
register int 	i,size;
XkbSectionPtr	section;

    for (i=size=0,section=geom->sections;i<geom->num_sections;i++,section++) {
	size+= SIZEOF(xkbSectionWireDesc);
	if (section->rows) {
	    int		r;
	    XkbRowPtr	row;
	    for (r=0,row=section->rows;r<section->num_rows;row++,r++) {
		size+= SIZEOF(xkbRowWireDesc);
		size+= row->num_keys*SIZEOF(xkbKeyWireDesc);
	    }
	}
	if (section->doodads)
	    size+= XkbSizeGeomDoodads(section->num_doodads,section->doodads);
	if (section->overlays) {
	    int			o;
	    XkbOverlayPtr	ol;
	    for (o=0,ol=section->overlays;o<section->num_overlays;o++,ol++) {
		int			r;
		XkbOverlayRowPtr	row;
		size+= SIZEOF(xkbOverlayWireDesc);
		for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) {
		   size+= SIZEOF(xkbOverlayRowWireDesc);
		   size+= row->num_keys*SIZEOF(xkbOverlayKeyWireDesc);
		}
	    }
	}
    }
    return size;
}


CheckKeyActions(	XkbDescPtr	xkb,
			xkbSetMapReq *	req,
			int		nTypes,
			CARD8 *		mapWidths,
			CARD16 *	symsPerKey,
			CARD8 **	wireRtrn,
			int *		nActsRtrn)
{
int			 nActs;
CARD8 *			 wire = *wireRtrn;
register unsigned	 i;

    if (!(XkbKeyActionsMask&req->present))
	return 1;
    CHK_REQ_KEY_RANGE2(0x21,req->firstKeyAct,req->nKeyActs,req,(*nActsRtrn),0);
    for (nActs=i=0;i<req->nKeyActs;i++) {
	if (wire[0]!=0) {
	    if (wire[0]==symsPerKey[i+req->firstKeyAct])
		nActs+= wire[0];
	    else {
		*nActsRtrn= _XkbErrCode3(0x23,i+req->firstKeyAct,wire[0]);
		return 0;
	    }
	}
	wire++;
    }
    if (req->nKeyActs%4)
	wire+= 4-(req->nKeyActs%4);
    *wireRtrn = (CARD8 *)(((XkbAnyAction *)wire)+nActs);
    *nActsRtrn = nActs;
    return 1;
}


ProcXkbGetControls(ClientPtr client)
{
    xkbGetControlsReply rep;
    XkbControlsPtr	xkb;
    DeviceIntPtr 	dev;
    register int 	n;

    REQUEST(xkbGetControlsReq);
    REQUEST_SIZE_MATCH(xkbGetControlsReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);

    xkb = dev->key->xkbInfo->desc->ctrls;
    rep.type = X_Reply;
    rep.length = (SIZEOF(xkbGetControlsReply)-
		  SIZEOF(xGenericReply)) >> 2;
    rep.sequenceNumber = client->sequence;
    rep.deviceID = ((DeviceIntPtr)dev)->id;
    rep.numGroups = xkb->num_groups;
    rep.groupsWrap = xkb->groups_wrap;
    rep.internalMods = xkb->internal.mask;
    rep.ignoreLockMods = xkb->ignore_lock.mask;
    rep.internalRealMods = xkb->internal.real_mods;
    rep.ignoreLockRealMods = xkb->ignore_lock.real_mods;
    rep.internalVMods = xkb->internal.vmods;
    rep.ignoreLockVMods = xkb->ignore_lock.vmods;
    rep.enabledCtrls = xkb->enabled_ctrls;
    rep.repeatDelay = xkb->repeat_delay;
    rep.repeatInterval = xkb->repeat_interval;
    rep.slowKeysDelay = xkb->slow_keys_delay;
    rep.debounceDelay = xkb->debounce_delay;
    rep.mkDelay = xkb->mk_delay;
    rep.mkInterval = xkb->mk_interval;
    rep.mkTimeToMax = xkb->mk_time_to_max;
    rep.mkMaxSpeed = xkb->mk_max_speed;
    rep.mkCurve = xkb->mk_curve;
    rep.mkDfltBtn = xkb->mk_dflt_btn;
    rep.axTimeout = xkb->ax_timeout;
    rep.axtCtrlsMask = xkb->axt_ctrls_mask;
    rep.axtCtrlsValues = xkb->axt_ctrls_values;
    rep.axtOptsMask = xkb->axt_opts_mask;
    rep.axtOptsValues = xkb->axt_opts_values;
    rep.axOptions = xkb->ax_options;
    memcpy(rep.perKeyRepeat,xkb->per_key_repeat,XkbPerKeyBitArraySize);
    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
	swapl(&rep.length,n);
	swaps(&rep.internalVMods, n);
	swaps(&rep.ignoreLockVMods, n);
	swapl(&rep.enabledCtrls, n);
	swaps(&rep.repeatDelay, n);
	swaps(&rep.repeatInterval, n);
	swaps(&rep.slowKeysDelay, n);
	swaps(&rep.debounceDelay, n);
	swaps(&rep.mkDelay, n);
	swaps(&rep.mkInterval, n);
	swaps(&rep.mkTimeToMax, n);
	swaps(&rep.mkMaxSpeed, n);
	swaps(&rep.mkCurve, n);
	swaps(&rep.axTimeout, n);
	swapl(&rep.axtCtrlsMask, n);
	swapl(&rep.axtCtrlsValues, n);
	swaps(&rep.axtOptsMask, n);
	swaps(&rep.axtOptsValues, n);
	swaps(&rep.axOptions, n);
    }
    WriteToClient(client, SIZEOF(xkbGetControlsReply), (char *)&rep);
    return(client->noClientException);
}


SetDeviceIndicators(	char *			wire,
			DeviceIntPtr		dev,
			unsigned		changed,
			int			num,
			int *			status_rtrn,
			ClientPtr		client,
			xkbExtensionDeviceNotify *ev)
{
xkbDeviceLedsWireDesc *		ledWire;
int				i;
XkbEventCauseRec		cause;
unsigned			namec,mapc,statec;
xkbExtensionDeviceNotify	ed;
XkbChangesRec			changes;
DeviceIntPtr			kbd;

    bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify));
    bzero((char *)&changes,sizeof(XkbChangesRec));
    XkbSetCauseXkbReq(&cause,X_kbSetDeviceInfo,client);
    ledWire= (xkbDeviceLedsWireDesc *)wire;
    for (i=0;i<num;i++) {
	register int			n;
	register unsigned 		bit;
	CARD32 *			atomWire;
	xkbIndicatorMapWireDesc *	mapWire;
	XkbSrvLedInfoPtr		sli;

	namec= mapc= statec= 0;
    	sli= XkbFindSrvLedInfo(dev,ledWire->ledClass,ledWire->ledID,
						XkbXI_IndicatorMapsMask);
	if (!sli) {
	    /* SHOULD NEVER HAPPEN!! */
	    return (char *)ledWire;
	}

	atomWire= (CARD32 *)&ledWire[1];
	if (changed&XkbXI_IndicatorNamesMask) {
	    namec= sli->namesPresent|ledWire->namesPresent;
	    bzero((char *)sli->names,XkbNumIndicators*sizeof(Atom));
	}
	if (ledWire->namesPresent) {
	    sli->namesPresent= ledWire->namesPresent;
	    bzero((char *)sli->names,XkbNumIndicators*sizeof(Atom));
	    for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) {
		if (ledWire->namesPresent&bit) {
		     sli->names[n]= (Atom)*atomWire;
		     if (sli->names[n]==None)
			ledWire->namesPresent&= ~bit;
		     atomWire++;
		}
	    }
	}
	mapWire= (xkbIndicatorMapWireDesc *)atomWire;
	if (changed&XkbXI_IndicatorMapsMask) {
	    mapc= sli->mapsPresent|ledWire->mapsPresent;
	    sli->mapsPresent= ledWire->mapsPresent;
	    bzero((char*)sli->maps,XkbNumIndicators*sizeof(XkbIndicatorMapRec));
	}
	if (ledWire->mapsPresent) {
	    for (n=0,bit=1;n<XkbNumIndicators;n++,bit<<=1) {
		if (ledWire->mapsPresent&bit) {
		    sli->maps[n].flags=		mapWire->flags;
		    sli->maps[n].which_groups=	mapWire->whichGroups;
		    sli->maps[n].groups=	mapWire->groups;
		    sli->maps[n].which_mods=	mapWire->whichMods;
		    sli->maps[n].mods.mask=	mapWire->mods;
		    sli->maps[n].mods.real_mods=mapWire->realMods;
		    sli->maps[n].mods.vmods=	mapWire->virtualMods;
		    sli->maps[n].ctrls=		mapWire->ctrls;
		    mapWire++;
		}
	    }
	}
	if (changed&XkbXI_IndicatorStateMask) {
	    statec= sli->effectiveState^ledWire->state;
	    sli->explicitState&= ~statec;
	    sli->explicitState|= (ledWire->state&statec);
	}
	if (namec)
	    XkbApplyLedNameChanges(dev,sli,namec,&ed,&changes,&cause);
	if (mapc)
	    XkbApplyLedMapChanges(dev,sli,mapc,&ed,&changes,&cause);
	if (statec)
	    XkbApplyLedStateChanges(dev,sli,statec,&ed,&changes,&cause);

	kbd= dev;
	if ((sli->flags&XkbSLI_HasOwnState)==0)
	    kbd = inputInfo.keyboard;

	XkbFlushLedEvents(dev,kbd,sli,&ed,&changes,&cause);
	ledWire= (xkbDeviceLedsWireDesc *)mapWire;
    }
    return (char *)ledWire;
}


XkbWriteGeomOverlay(char *wire,XkbOverlayPtr ol,Bool swap)
{
register int		r;
XkbOverlayRowPtr	row;
xkbOverlayWireDesc *	olWire;

   olWire= (xkbOverlayWireDesc *)wire;
   olWire->name= ol->name;
   olWire->nRows= ol->num_rows;
   if (swap) {
	register int n;
	swapl(&olWire->name,n);
   }
   wire= (char *)&olWire[1];
   for (r=0,row=ol->rows;r<ol->num_rows;r++,row++) {
   	unsigned int		k;
	XkbOverlayKeyPtr	key;
	xkbOverlayRowWireDesc *	rowWire;
	rowWire= (xkbOverlayRowWireDesc *)wire;
	rowWire->rowUnder= row->row_under;
	rowWire->nKeys= row->num_keys;
	wire= (char *)&rowWire[1];
	for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
	    xkbOverlayKeyWireDesc *	keyWire;
	    keyWire= (xkbOverlayKeyWireDesc *)wire;
	    memcpy(keyWire->over,key->over.name,XkbKeyNameLength);
	    memcpy(keyWire->under,key->under.name,XkbKeyNameLength);
	    wire= (char *)&keyWire[1];
	}
   }
   return wire;
}


ProcXkbSelectEvents(ClientPtr client)
{
    unsigned		legal;
    DeviceIntPtr 	dev;
    XkbInterestPtr	masks;
    REQUEST(xkbSelectEventsReq);

    REQUEST_AT_LEAST_SIZE(xkbSelectEventsReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixUseAccess);

    if (((stuff->affectWhich&XkbMapNotifyMask)!=0)&&(stuff->affectMap)) {
	client->mapNotifyMask&= ~stuff->affectMap;
	client->mapNotifyMask|= (stuff->affectMap&stuff->map);
    }
    if ((stuff->affectWhich&(~XkbMapNotifyMask))==0)
	return client->noClientException;

    masks = XkbFindClientResource((DevicePtr)dev,client);
    if (!masks){
	XID id = FakeClientID(client->index);
	AddResource(id,RT_XKBCLIENT,dev);
	masks= XkbAddClientResource((DevicePtr)dev,client,id);
    }
    if (masks) {
	union {
	    CARD8	*c8;
	    CARD16	*c16;
	    CARD32	*c32;
	} from,to;
	register unsigned bit,ndx,maskLeft,dataLeft,size;

	from.c8= (CARD8 *)&stuff[1];
	dataLeft= (stuff->length*4)-SIZEOF(xkbSelectEventsReq);
	maskLeft= (stuff->affectWhich&(~XkbMapNotifyMask));
	for (ndx=0,bit=1; (maskLeft!=0); ndx++, bit<<=1) {
	    if ((bit&maskLeft)==0)
		continue;
	    maskLeft&= ~bit;
	    switch (ndx) {
		case XkbNewKeyboardNotify:
		    to.c16= &client->newKeyboardNotifyMask;
		    legal= XkbAllNewKeyboardEventsMask;
		    size= 2;
		    break;
		case XkbStateNotify:
		    to.c16= &masks->stateNotifyMask;
		    legal= XkbAllStateEventsMask;
		    size= 2;
		    break;
		case XkbControlsNotify:
		    to.c32= &masks->ctrlsNotifyMask;
		    legal= XkbAllControlEventsMask;
		    size= 4;
		    break;
		case XkbIndicatorStateNotify:
		    to.c32= &masks->iStateNotifyMask;
		    legal= XkbAllIndicatorEventsMask;
		    size= 4;
		    break;
		case XkbIndicatorMapNotify:
		    to.c32= &masks->iMapNotifyMask;
		    legal= XkbAllIndicatorEventsMask;
		    size= 4;
		    break;
		case XkbNamesNotify:
		    to.c16= &masks->namesNotifyMask;
		    legal= XkbAllNameEventsMask;
		    size= 2;
		    break;
		case XkbCompatMapNotify:
		    to.c8= &masks->compatNotifyMask;
		    legal= XkbAllCompatMapEventsMask;
		    size= 1;
		    break;
		case XkbBellNotify:
		    to.c8= &masks->bellNotifyMask;
		    legal= XkbAllBellEventsMask;
		    size= 1;
		    break;
		case XkbActionMessage:
		    to.c8= &masks->actionMessageMask;
		    legal= XkbAllActionMessagesMask;
		    size= 1;
		    break;
		case XkbAccessXNotify:
		    to.c16= &masks->accessXNotifyMask;
		    legal= XkbAllAccessXEventsMask;
		    size= 2;
		    break;
		case XkbExtensionDeviceNotify:
		    to.c16= &masks->extDevNotifyMask;
		    legal= XkbAllExtensionDeviceEventsMask;
		    size= 2;
		    break;
		default:
		    client->errorValue = _XkbErrCode2(33,bit);
		    return BadValue;
	    }

	    if (stuff->clear&bit) {
		if (size==2)		to.c16[0]= 0;
		else if (size==4)	to.c32[0]= 0;
		else			to.c8[0]=  0;
	    }
	    else if (stuff->selectAll&bit) {
		if (size==2)		to.c16[0]= ~0;
		else if (size==4)	to.c32[0]= ~0;
		else			to.c8[0]=  ~0;
	    }
	    else {
		if (dataLeft<(size*2))
		    return BadLength;
		if (size==2) {
		    CHK_MASK_MATCH(ndx,from.c16[0],from.c16[1]);
		    CHK_MASK_LEGAL(ndx,from.c16[0],legal);
		    to.c16[0]&= ~from.c16[0];
		    to.c16[0]|= (from.c16[0]&from.c16[1]);
		}
		else if (size==4) {
		    CHK_MASK_MATCH(ndx,from.c32[0],from.c32[1]);
		    CHK_MASK_LEGAL(ndx,from.c32[0],legal);
		    to.c32[0]&= ~from.c32[0];
		    to.c32[0]|= (from.c32[0]&from.c32[1]);
		}
		else  {
		    CHK_MASK_MATCH(ndx,from.c8[0],from.c8[1]);
		    CHK_MASK_LEGAL(ndx,from.c8[0],legal);
		    to.c8[0]&= ~from.c8[0];
		    to.c8[0]|= (from.c8[0]&from.c8[1]);
		    size= 2;
		}
		from.c8+= (size*2);
		dataLeft-= (size*2);
	    }
	}
	if (dataLeft>2) {
	    ErrorF("[xkb] Extra data (%d bytes) after SelectEvents\n",dataLeft);
	    return BadLength;
	}
	return client->noClientException;
    }
    return BadAlloc;
}


XkbSizeKeyTypes(XkbDescPtr xkb,xkbGetMapReply *rep)
{
    XkbKeyTypeRec 	*type;
    unsigned		i,len;

    len= 0;
    if (((rep->present&XkbKeyTypesMask)==0)||(rep->nTypes<1)||
	(!xkb)||(!xkb->map)||(!xkb->map->types)) {
	rep->present&= ~XkbKeyTypesMask;
	rep->firstType= rep->nTypes= 0;
	return 0;
    }
    type= &xkb->map->types[rep->firstType];
    for (i=0;i<rep->nTypes;i++,type++){
	len+= SIZEOF(xkbKeyTypeWireDesc);
	if (type->map_count>0) {
	    len+= (type->map_count*SIZEOF(xkbKTMapEntryWireDesc));
	    if (type->preserve)
		len+= (type->map_count*SIZEOF(xkbModsWireDesc));
	}
    }
    return len;
}


ProcXkbGetIndicatorMap(ClientPtr client)
{
xkbGetIndicatorMapReply rep;
DeviceIntPtr		dev;
XkbDescPtr		xkb;
XkbIndicatorPtr		leds;

    REQUEST(xkbGetIndicatorMapReq);
    REQUEST_SIZE_MATCH(xkbGetIndicatorMapReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);

    xkb= dev->key->xkbInfo->desc;
    leds= xkb->indicators;

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length = 0;
    rep.deviceID = dev->id;
    rep.which = stuff->which;
    XkbComputeGetIndicatorMapReplySize(leds,&rep);
    return XkbSendIndicatorMap(client,leds,&rep);
}


XkbWriteKeyTypes(	XkbDescPtr		xkb,
			xkbGetMapReply *	rep,
			char *			buf,
			ClientPtr 		client)
{
    XkbKeyTypePtr	type;
    unsigned		i;
    xkbKeyTypeWireDesc *wire;

    type= &xkb->map->types[rep->firstType];
    for (i=0;i<rep->nTypes;i++,type++) {
	register unsigned n;
	wire= (xkbKeyTypeWireDesc *)buf;
	wire->mask = type->mods.mask;
	wire->realMods = type->mods.real_mods;
	wire->virtualMods = type->mods.vmods;
	wire->numLevels = type->num_levels;
	wire->nMapEntries = type->map_count;
	wire->preserve = (type->preserve!=NULL);
	if (client->swapped) {
	    register int n;
	    swaps(&wire->virtualMods,n);
	}

	buf= (char *)&wire[1];
	if (wire->nMapEntries>0) {
	    xkbKTMapEntryWireDesc *	wire;
	    XkbKTMapEntryPtr		entry;
	    wire= (xkbKTMapEntryWireDesc *)buf;
	    entry= type->map;
	    for (n=0;n<type->map_count;n++,wire++,entry++) {
		wire->active= entry->active;
		wire->mask= entry->mods.mask;
		wire->level= entry->level;
		wire->realMods= entry->mods.real_mods;
		wire->virtualMods= entry->mods.vmods;
		if (client->swapped) {
		    register int n;
		    swaps(&wire->virtualMods,n);
		}
	    }
	    buf= (char *)wire;
	    if (type->preserve!=NULL) {
		xkbModsWireDesc *	pwire;
		XkbModsPtr		preserve;
		pwire= (xkbModsWireDesc *)buf;
		preserve= type->preserve;
		for (n=0;n<type->map_count;n++,pwire++,preserve++) {
		    pwire->mask= preserve->mask;
		    pwire->realMods= preserve->real_mods;
		    pwire->virtualMods= preserve->vmods;
		    if (client->swapped) {
			register int n;
			swaps(&pwire->virtualMods,n);
		    }
		}
		buf= (char *)pwire;
	    }
	}
    }
    return buf;
}


_XkbSetGeometry(ClientPtr client, DeviceIntPtr dev, xkbSetGeometryReq *stuff)
{
    XkbDescPtr		xkb;
    Bool		new_name;
    xkbNewKeyboardNotify	nkn;
    XkbGeometryPtr	geom,old;
    XkbGeometrySizesRec	sizes;
    Status		status;

    xkb= dev->key->xkbInfo->desc;
    old= xkb->geom;
    xkb->geom= NULL;

    sizes.which=		XkbGeomAllMask;
    sizes.num_properties=	stuff->nProperties;
    sizes.num_colors=	stuff->nColors;
    sizes.num_shapes=	stuff->nShapes;
    sizes.num_sections=	stuff->nSections;
    sizes.num_doodads=	stuff->nDoodads;
    sizes.num_key_aliases=	stuff->nKeyAliases;
    if ((status= XkbAllocGeometry(xkb,&sizes))!=Success) {
        xkb->geom= old;
        return status;
    }
    geom= xkb->geom;
    geom->name= stuff->name;
    geom->width_mm= stuff->widthMM;
    geom->height_mm= stuff->heightMM;
    if ((status= _CheckSetGeom(geom,stuff,client))!=Success) {
        XkbFreeGeometry(geom,XkbGeomAllMask,True);
        xkb->geom= old;
        return status;
    }
    new_name= (xkb->names->geometry!=geom->name);
    xkb->names->geometry= geom->name;
    if (old)
        XkbFreeGeometry(old,XkbGeomAllMask,True);
    if (new_name) {
        xkbNamesNotify	nn;
        bzero(&nn,sizeof(xkbNamesNotify));
        nn.changed= XkbGeometryNameMask;
        XkbSendNamesNotify(dev,&nn);
    }
    nkn.deviceID= nkn.oldDeviceID= dev->id;
    nkn.minKeyCode= nkn.oldMinKeyCode= xkb->min_key_code;
    nkn.maxKeyCode= nkn.oldMaxKeyCode= xkb->max_key_code;
    nkn.requestMajor=	XkbReqCode;
    nkn.requestMinor=	X_kbSetGeometry;
    nkn.changed=	XkbNKN_GeometryMask;
    XkbSendNewKeyboardNotify(dev,&nkn);
    return Success;
}


ProcXkbSetDeviceInfo(ClientPtr client)
{
    unsigned int        change;
    DeviceIntPtr        dev;
    int                 rc;

    REQUEST(xkbSetDeviceInfoReq);
    REQUEST_AT_LEAST_SIZE(xkbSetDeviceInfoReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    change = stuff->change;

    CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
    CHK_MASK_LEGAL(0x01,change,XkbXI_AllFeaturesMask);

    rc = _XkbSetDeviceInfoCheck(client, dev, stuff);

    if (rc != Success)
        return rc;

    if (stuff->deviceSpec == XkbUseCoreKbd || stuff->deviceSpec == XkbUseCorePtr)
    {
        DeviceIntPtr other;
        for (other = inputInfo.devices; other; other = other->next)
        {
            if (((other != dev) && !other->isMaster && (other->u.master == dev)) &&
                ((stuff->deviceSpec == XkbUseCoreKbd && other->key) ||
                (stuff->deviceSpec == XkbUseCorePtr && other->button)))
            {
                rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess);
                if (rc == Success)
                {
                    rc = _XkbSetDeviceInfoCheck(client, other, stuff);
                    if (rc != Success)
                        return rc;
                }
            }
        }
    }

    /* checks done, apply */
    rc = _XkbSetDeviceInfo(client, dev, stuff);
    if (rc != Success)
        return rc;

    if (stuff->deviceSpec == XkbUseCoreKbd || stuff->deviceSpec == XkbUseCorePtr)
    {
        DeviceIntPtr other;
        for (other = inputInfo.devices; other; other = other->next)
        {
            if (((other != dev) && !other->isMaster && (other->u.master == dev)) &&
                ((stuff->deviceSpec == XkbUseCoreKbd && other->key) ||
                (stuff->deviceSpec == XkbUseCorePtr && other->button)))
            {
                rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess);
                if (rc == Success)
                {
                    rc = _XkbSetDeviceInfo(client, other, stuff);
                    if (rc != Success)
                        return rc;
                }
            }
        }
    }

    return client->noClientException;
}


_XkbCheckTypeName(Atom name,int typeNdx)
{
char *	str;

    str= NameForAtom(name);
    if ((strcmp(str,"ONE_LEVEL")==0)||(strcmp(str,"TWO_LEVEL")==0)||
	(strcmp(str,"ALPHABETIC")==0)||(strcmp(str,"KEYPAD")==0))
	return False;
    return True;
}


CheckKeySyms(	ClientPtr		client,
		XkbDescPtr		xkb,
		xkbSetMapReq *		req,
		int			nTypes,
		CARD8 *	 		mapWidths,
		CARD16 *	 	symsPerKey,
		xkbSymMapWireDesc **	wireRtrn,
		int *			errorRtrn)
{
register unsigned	i;
XkbSymMapPtr		map;
xkbSymMapWireDesc*	wire = *wireRtrn;

    if (!(XkbKeySymsMask&req->present))
	return 1;
    CHK_REQ_KEY_RANGE2(0x11,req->firstKeySym,req->nKeySyms,req,(*errorRtrn),0);
    map = &xkb->map->key_sym_map[xkb->min_key_code];
    for (i=xkb->min_key_code;i<(unsigned)req->firstKeySym;i++,map++) {
	register int g,ng,w;
	ng= XkbNumGroups(map->group_info);
	for (w=g=0;g<ng;g++) {
	    if (map->kt_index[g]>=(unsigned)nTypes) {
		*errorRtrn = _XkbErrCode4(0x13,i,g,map->kt_index[g]);
		return 0;
	    }
	    if (mapWidths[map->kt_index[g]]>w)
		w= mapWidths[map->kt_index[g]];
	}
	symsPerKey[i] = w*ng;
    }
    for (i=0;i<req->nKeySyms;i++) {
	KeySym *pSyms;
	register unsigned nG;
	if (client->swapped) {
	    swaps(&wire->nSyms,nG);
	}
	nG = XkbNumGroups(wire->groupInfo);
	if (nG>XkbNumKbdGroups) {
	    *errorRtrn = _XkbErrCode3(0x14,i+req->firstKeySym,nG);
	    return 0;
	}
	if (nG>0) {
	    register int g,w;
	    for (g=w=0;g<nG;g++) {
		if (wire->ktIndex[g]>=(unsigned)nTypes) {
		    *errorRtrn= _XkbErrCode4(0x15,i+req->firstKeySym,g,
		    					   wire->ktIndex[g]);
		    return 0;
		}
		if (mapWidths[wire->ktIndex[g]]>w)
		    w= mapWidths[wire->ktIndex[g]];
	    }
	    if (wire->width!=w) {
		*errorRtrn= _XkbErrCode3(0x16,i+req->firstKeySym,wire->width);
		return 0;
	    }
	    w*= nG;
	    symsPerKey[i+req->firstKeySym] = w;
	    if (w!=wire->nSyms) {
		*errorRtrn=_XkbErrCode4(0x16,i+req->firstKeySym,wire->nSyms,w);
		return 0;
	    }
	}
	else if (wire->nSyms!=0) {
	    *errorRtrn = _XkbErrCode3(0x17,i+req->firstKeySym,wire->nSyms);
	    return 0;
	}
	pSyms = (KeySym *)&wire[1];
	wire = (xkbSymMapWireDesc *)&pSyms[wire->nSyms];
    }

    map = &xkb->map->key_sym_map[i];
    for (;i<=(unsigned)xkb->max_key_code;i++,map++) {
	register int g,nG,w;
	nG= XkbKeyNumGroups(xkb,i);
	for (w=g=0;g<nG;g++)  {
	    if (map->kt_index[g]>=(unsigned)nTypes) {
		*errorRtrn = _XkbErrCode4(0x18,i,g,map->kt_index[g]);
		return 0;
	    }
	    if (mapWidths[map->kt_index[g]]>w)
		    w= mapWidths[map->kt_index[g]];
	}
	symsPerKey[i] = w*nG;
    }
    *wireRtrn = wire;
    return 1;
}


_XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev,
                 xkbSetCompatMapReq *req, char* data, BOOL dryRun)
{
    XkbSrvInfoPtr       xkbi;
    XkbDescPtr          xkb;
    XkbCompatMapPtr     compat;
    int                 nGroups;
    unsigned            i,bit;

    xkbi = dev->key->xkbInfo;
    xkb = xkbi->desc;
    compat = xkb->compat;

    if ((req->nSI>0)||(req->truncateSI)) {
	xkbSymInterpretWireDesc *wire;
	if (req->firstSI>compat->num_si) {
	    client->errorValue = _XkbErrCode2(0x02,compat->num_si);
	    return BadValue;
	}
	wire= (xkbSymInterpretWireDesc *)data;
	wire+= req->nSI;
	data = (char *)wire;
    }

    nGroups= 0;
    if (req->groups!=0) {
	for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
	    if ( req->groups&bit )
		nGroups++;
	}
    }
    data+= nGroups*SIZEOF(xkbModsWireDesc);
    if (((data-((char *)req))/4)!=req->length) {
	return BadLength;
    }

    /* Done all the checks we can do */
    if (dryRun)
        return Success;

    data = (char *)&req[1];
    if (req->nSI>0) {
	xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *)data;
	XkbSymInterpretPtr	sym;
	if ((unsigned)(req->firstSI+req->nSI)>compat->num_si) {
	    compat->num_si= req->firstSI+req->nSI;
	    compat->sym_interpret= _XkbTypedRealloc(compat->sym_interpret,
						   compat->num_si,
						   XkbSymInterpretRec);
	    if (!compat->sym_interpret) {
		compat->num_si= 0;
		return BadAlloc;
	    }
	}
	else if (req->truncateSI) {
	    compat->num_si = req->firstSI+req->nSI;
	}
	sym = &compat->sym_interpret[req->firstSI];
	for (i=0;i<req->nSI;i++,wire++,sym++) {
	    if (client->swapped) {
		int n;
		swapl(&wire->sym,n);
	    }
	    sym->sym= wire->sym;
	    sym->mods= wire->mods;
	    sym->match= wire->match;
	    sym->flags= wire->flags;
	    sym->virtual_mod= wire->virtualMod;
	    memcpy((char *)&sym->act,(char *)&wire->act,
                   SIZEOF(xkbActionWireDesc));
	}
	data = (char *)wire;
    }
    else if (req->truncateSI) {
	compat->num_si = req->firstSI;
    }

    if (req->groups!=0) {
	unsigned i, bit;
	xkbModsWireDesc *wire = (xkbModsWireDesc *)data;
	for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
	    if (req->groups & bit) {
		if (client->swapped) {
		    int n;
		    swaps(&wire->virtualMods,n);
		}
		compat->groups[i].mask= wire->realMods;
		compat->groups[i].real_mods= wire->realMods;
		compat->groups[i].vmods= wire->virtualMods;
		if (wire->virtualMods!=0) {
		    unsigned tmp;
		    tmp= XkbMaskForVMask(xkb,wire->virtualMods);
		    compat->groups[i].mask|= tmp;
		}
		data+= SIZEOF(xkbModsWireDesc);
		wire= (xkbModsWireDesc *)data;
	    }
	}
    }
    i= XkbPaddedSize((data-((char *)req)));
    if ((i/4)!=req->length) {
	ErrorF("[xkb] Internal length error on read in _XkbSetCompatMap\n");
	return BadLength;
    }

    if (dev->xkb_interest) {
	xkbCompatMapNotify ev;
	ev.deviceID = dev->id;
	ev.changedGroups = req->groups;
	ev.firstSI = req->firstSI;
	ev.nSI = req->nSI;
	ev.nTotalSI = compat->num_si;
	XkbSendCompatMapNotify(dev,&ev);
    }

    if (req->recomputeActions) {
	XkbChangesRec		change;
	unsigned		check;
	XkbEventCauseRec	cause;

	XkbSetCauseXkbReq(&cause,X_kbSetCompatMap,client);
	bzero(&change,sizeof(XkbChangesRec));
	XkbUpdateActions(dev,xkb->min_key_code,XkbNumKeys(xkb),&change,&check,
									&cause);
	if (check)
	    XkbCheckSecondaryEffects(xkbi,check,&change,&cause);
	XkbUpdateCoreDescription(dev,False);
	XkbSendNotification(dev,&change,&cause);
    }
    return Success;
}


XkbSizeGeomDoodads(int num_doodads,XkbDoodadPtr doodad)
{
register int	i,size;

    for (i=size=0;i<num_doodads;i++,doodad++) {
	size+= SIZEOF(xkbAnyDoodadWireDesc);
	if (doodad->any.type==XkbTextDoodad) {
	    size+= XkbSizeCountedString(doodad->text.text);
	    size+= XkbSizeCountedString(doodad->text.font);
	}
	else if (doodad->any.type==XkbLogoDoodad) {
	    size+= XkbSizeCountedString(doodad->logo.logo_name);
	}
    }
    return size;
}


XkbWriteGeomSections(char *wire,XkbGeometryPtr geom,Bool swap)
{
register int		i;
XkbSectionPtr		section;
xkbSectionWireDesc *	sectionWire;

    for (i=0,section=geom->sections;i<geom->num_sections;i++,section++) {
	sectionWire= (xkbSectionWireDesc *)wire;
	sectionWire->name= section->name;
	sectionWire->top= section->top;
	sectionWire->left= section->left;
	sectionWire->width= section->width;
	sectionWire->height= section->height;
	sectionWire->angle= section->angle;
	sectionWire->priority= section->priority;
	sectionWire->nRows= section->num_rows;
	sectionWire->nDoodads= section->num_doodads;
	sectionWire->nOverlays= section->num_overlays;
	sectionWire->pad= 0;
	if (swap) {
	    register int n;
	    swapl(&sectionWire->name,n);
	    swaps(&sectionWire->top,n);
	    swaps(&sectionWire->left,n);
	    swaps(&sectionWire->width,n);
	    swaps(&sectionWire->height,n);
	    swaps(&sectionWire->angle,n);
	}
	wire= (char *)&sectionWire[1];
	if (section->rows) {
	    int			r;
	    XkbRowPtr		row;
	    xkbRowWireDesc *	rowWire;
	    for (r=0,row=section->rows;r<section->num_rows;r++,row++) {
		rowWire= (xkbRowWireDesc *)wire;
		rowWire->top= row->top;
		rowWire->left= row->left;
		rowWire->nKeys= row->num_keys;
		rowWire->vertical= row->vertical;
		rowWire->pad= 0;
		if (swap) {
		    register int n;
		    swaps(&rowWire->top,n);
		    swaps(&rowWire->left,n);
		}
		wire= (char *)&rowWire[1];
		if (row->keys) {
		    int			k;
		    XkbKeyPtr		key;
		    xkbKeyWireDesc *	keyWire;
		    keyWire= (xkbKeyWireDesc *)wire;
		    for (k=0,key=row->keys;k<row->num_keys;k++,key++) {
			memcpy(keyWire[k].name,key->name.name,XkbKeyNameLength);
			keyWire[k].gap= key->gap;
			keyWire[k].shapeNdx= key->shape_ndx;
			keyWire[k].colorNdx= key->color_ndx;
			if (swap) {
			    register int n;
			    swaps(&keyWire[k].gap,n);
			}
		    }
		    wire= (char *)&keyWire[row->num_keys];
		}
	    }
	}
	if (section->doodads) {
	    wire= XkbWriteGeomDoodads(wire,
	    			      section->num_doodads,section->doodads,
				      swap);
	}
	if (section->overlays) {
	    register int o;
	    for (o=0;o<section->num_overlays;o++) {
		wire= XkbWriteGeomOverlay(wire,&section->overlays[o],swap);
	    }
	}
    }
    return wire;
}


XkbSendNames(ClientPtr client,XkbDescPtr xkb,xkbGetNamesReply *rep)
{
register unsigned 	i,length,which;
char *			start;
char *			desc;
register int            n;

    length= rep->length*4;
    which= rep->which;
    if (client->swapped) {
	swaps(&rep->sequenceNumber,n);
	swapl(&rep->length,n);
	swapl(&rep->which,n);
	swaps(&rep->virtualMods,n);
	swapl(&rep->indicators,n);
    }

    start = desc = (char *)xalloc(length);
    if ( !start )
	return BadAlloc;
    if (xkb->names) {
        if (which&XkbKeycodesNameMask) {
            *((CARD32 *)desc)= xkb->names->keycodes;
            if (client->swapped) {
                swapl(desc,n);
            }
            desc+= 4;
        }
        if (which&XkbGeometryNameMask)  {
            *((CARD32 *)desc)= xkb->names->geometry;
            if (client->swapped) {
                swapl(desc,n);
            }
            desc+= 4;
        }
        if (which&XkbSymbolsNameMask) {
            *((CARD32 *)desc)= xkb->names->symbols;
            if (client->swapped) {
                swapl(desc,n);
            }
            desc+= 4;
        }
        if (which&XkbPhysSymbolsNameMask) {
            register CARD32 *atm= (CARD32 *)desc;
            atm[0]= (CARD32)xkb->names->phys_symbols;
            if (client->swapped) {
                swapl(&atm[0],n);
            }
            desc+= 4;
        }
        if (which&XkbTypesNameMask) {
            *((CARD32 *)desc)= (CARD32)xkb->names->types;
            if (client->swapped) {
                swapl(desc,n);
            }
            desc+= 4;
        }
        if (which&XkbCompatNameMask) {
            *((CARD32 *)desc)= (CARD32)xkb->names->compat;
            if (client->swapped) {
                swapl(desc,n);
            }
            desc+= 4;
        }
        if (which&XkbKeyTypeNamesMask) {
            register CARD32 *atm= (CARD32 *)desc;
            register XkbKeyTypePtr type= xkb->map->types;

            for (i=0;i<xkb->map->num_types;i++,atm++,type++) {
                *atm= (CARD32)type->name;
                if (client->swapped) {
                    swapl(atm,n);
                }
            }
            desc= (char *)atm;
        }
        if (which&XkbKTLevelNamesMask && xkb->map) {
            XkbKeyTypePtr type = xkb->map->types;
            register CARD32 *atm;
            for (i=0;i<rep->nTypes;i++,type++) {
                *desc++ = type->num_levels;
            }
            desc+= XkbPaddedSize(rep->nTypes)-rep->nTypes;

            atm= (CARD32 *)desc;
            type = xkb->map->types;
            for (i=0;i<xkb->map->num_types;i++,type++) {
                register unsigned l;
                if (type->level_names) {
                    for (l=0;l<type->num_levels;l++,atm++) {
                        *atm= type->level_names[l];
                        if (client->swapped) {
                            swapl(atm,n);
                        }
                    }
                    desc+= type->num_levels*4;
                }
            }
        }
        if (which&XkbIndicatorNamesMask) {
            desc= _XkbWriteAtoms(desc,xkb->names->indicators,XkbNumIndicators,
                                 client->swapped);
        }
        if (which&XkbVirtualModNamesMask) {
            desc= _XkbWriteAtoms(desc,xkb->names->vmods,XkbNumVirtualMods,
                                 client->swapped);
        }
        if (which&XkbGroupNamesMask) {
            desc= _XkbWriteAtoms(desc,xkb->names->groups,XkbNumKbdGroups,
                                 client->swapped);
        }
        if (which&XkbKeyNamesMask) {
            for (i=0;i<rep->nKeys;i++,desc+= sizeof(XkbKeyNameRec)) {
                *((XkbKeyNamePtr)desc)= xkb->names->keys[i+rep->firstKey];
            }
        }
        if (which&XkbKeyAliasesMask) {
            XkbKeyAliasPtr	pAl;
            pAl= xkb->names->key_aliases;
            for (i=0;i<rep->nKeyAliases;i++,pAl++,desc+=2*XkbKeyNameLength) {
                *((XkbKeyAliasPtr)desc)= *pAl;
            }
        }
        if ((which&XkbRGNamesMask)&&(rep->nRadioGroups>0)) {
            register CARD32	*atm= (CARD32 *)desc;
            for (i=0;i<rep->nRadioGroups;i++,atm++) {
                *atm= (CARD32)xkb->names->radio_groups[i];
                if (client->swapped) {
                    swapl(atm,n);
                }
            }
            desc+= rep->nRadioGroups*4;
        }
    }

    if ((desc-start)!=(length)) {
	ErrorF("[xkb] BOGUS LENGTH in write names, expected %d, got %ld\n",
					length, (unsigned long)(desc-start));
    }
    WriteToClient(client, SIZEOF(xkbGetNamesReply), (char *)rep);
    WriteToClient(client, length, start);
    xfree((char *)start);
    return client->noClientException;
}


ProcXkbDispatch (ClientPtr client)
{
    REQUEST(xReq);
    switch (stuff->data)
    {
    case X_kbUseExtension:
	return ProcXkbUseExtension(client);
    case X_kbSelectEvents:
	return ProcXkbSelectEvents(client);
    case X_kbBell:
	return ProcXkbBell(client);
    case X_kbGetState:
	return ProcXkbGetState(client);
    case X_kbLatchLockState:
	return ProcXkbLatchLockState(client);
    case X_kbGetControls:
	return ProcXkbGetControls(client);
    case X_kbSetControls:
	return ProcXkbSetControls(client);
    case X_kbGetMap:
	return ProcXkbGetMap(client);
    case X_kbSetMap:
	return ProcXkbSetMap(client);
    case X_kbGetCompatMap:
	return ProcXkbGetCompatMap(client);
    case X_kbSetCompatMap:
	return ProcXkbSetCompatMap(client);
    case X_kbGetIndicatorState:
	return ProcXkbGetIndicatorState(client);
    case X_kbGetIndicatorMap:
	return ProcXkbGetIndicatorMap(client);
    case X_kbSetIndicatorMap:
	return ProcXkbSetIndicatorMap(client);
    case X_kbGetNamedIndicator:
	return ProcXkbGetNamedIndicator(client);
    case X_kbSetNamedIndicator:
	return ProcXkbSetNamedIndicator(client);
    case X_kbGetNames:
	return ProcXkbGetNames(client);
    case X_kbSetNames:
	return ProcXkbSetNames(client);
    case X_kbGetGeometry:
	return ProcXkbGetGeometry(client);
    case X_kbSetGeometry:
	return ProcXkbSetGeometry(client);
    case X_kbPerClientFlags:
	return ProcXkbPerClientFlags(client);
    case X_kbListComponents:
	return ProcXkbListComponents(client);
    case X_kbGetKbdByName:
	return ProcXkbGetKbdByName(client);
    case X_kbGetDeviceInfo:
	return ProcXkbGetDeviceInfo(client);
    case X_kbSetDeviceInfo:
	return ProcXkbSetDeviceInfo(client);
    case X_kbSetDebuggingFlags:
	return ProcXkbSetDebuggingFlags(client);
    default:
	return BadRequest;
    }
}


ProcXkbBell(ClientPtr client)
{
    REQUEST(xkbBellReq);
    DeviceIntPtr dev;
    WindowPtr	 pWin;
    int rc;

    REQUEST_SIZE_MATCH(xkbBellReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_BELL_DEVICE(dev, stuff->deviceSpec, client, DixBellAccess);
    CHK_ATOM_OR_NONE(stuff->name);

    /* device-independent checks request for sane values */
    if ((stuff->forceSound)&&(stuff->eventOnly)) {
	client->errorValue=_XkbErrCode3(0x1,stuff->forceSound,stuff->eventOnly);
	return BadMatch;
    }
    if (stuff->percent < -100 || stuff->percent > 100) {
	client->errorValue = _XkbErrCode2(0x2,stuff->percent);
	return BadValue;
    }
    if (stuff->duration<-1) {
	client->errorValue = _XkbErrCode2(0x3,stuff->duration);
	return BadValue;
    }
    if (stuff->pitch<-1) {
	client->errorValue = _XkbErrCode2(0x4,stuff->pitch);
	return BadValue;
    }

    if (stuff->bellClass == XkbDfltXIClass) {
	if (dev->kbdfeed!=NULL)
	     stuff->bellClass= KbdFeedbackClass;
	else stuff->bellClass= BellFeedbackClass;
    }

    if (stuff->window!=None) {
	rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
	if (rc != Success) {
	    client->errorValue= stuff->window;
	    return rc;
	}
    }
    else pWin= NULL;

    /* Client wants to ring a bell on the core keyboard?
       Ring the bell on the core keyboard (which does nothing, but if that
       fails the client is screwed anyway), and then on all extension devices.
       Fail if the core keyboard fails but not the extension devices.  this
       may cause some keyboards to ding and others to stay silent. Fix
       your client to use explicit keyboards to avoid this.

       dev is the device the client requested.
     */
    rc = _XkbBell(client, dev, pWin, stuff->bellClass, stuff->bellID,
                  stuff->pitch, stuff->duration, stuff->percent,
                  stuff->forceSound, stuff->eventOnly, stuff->name);

    if ((rc == Success) && ((stuff->deviceSpec == XkbUseCoreKbd) ||
                            (stuff->deviceSpec == XkbUseCorePtr)))
    {
        DeviceIntPtr other;
        for (other = inputInfo.devices; other; other = other->next)
        {
            if ((other != dev) && other->key && !other->isMaster && (other->u.master == dev))
            {
                rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixBellAccess);
                if (rc == Success)
                    _XkbBell(client, other, pWin, stuff->bellClass,
                             stuff->bellID, stuff->pitch, stuff->duration,
                             stuff->percent, stuff->forceSound,
                             stuff->eventOnly, stuff->name);
            }
        }
        rc = Success; /* reset to success, that's what we got for the VCK */
    }

    return rc;
}


ProcXkbGetMap(ClientPtr client)
{
    DeviceIntPtr	 dev;
    xkbGetMapReply	 rep;
    XkbDescRec		*xkb;
    int			 n,status;

    REQUEST(xkbGetMapReq);
    REQUEST_SIZE_MATCH(xkbGetMapReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
    CHK_MASK_OVERLAP(0x01,stuff->full,stuff->partial);
    CHK_MASK_LEGAL(0x02,stuff->full,XkbAllMapComponentsMask);
    CHK_MASK_LEGAL(0x03,stuff->partial,XkbAllMapComponentsMask);

    xkb= dev->key->xkbInfo->desc;
    bzero(&rep,sizeof(xkbGetMapReply));
    rep.type= X_Reply;
    rep.sequenceNumber= client->sequence;
    rep.length = (SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply))>>2;
    rep.deviceID = dev->id;
    rep.present = stuff->partial|stuff->full;
    rep.minKeyCode = xkb->min_key_code;
    rep.maxKeyCode = xkb->max_key_code;
    if ( stuff->full&XkbKeyTypesMask ) {
	rep.firstType = 0;
	rep.nTypes = xkb->map->num_types;
    }
    else if (stuff->partial&XkbKeyTypesMask) {
	if (((unsigned)stuff->firstType+stuff->nTypes)>xkb->map->num_types) {
	    client->errorValue = _XkbErrCode4(0x04,xkb->map->num_types,
					stuff->firstType,stuff->nTypes);
	    return BadValue;
	}
	rep.firstType = stuff->firstType;
	rep.nTypes = stuff->nTypes;
    }
    else rep.nTypes = 0;
    rep.totalTypes = xkb->map->num_types;

    n= XkbNumKeys(xkb);
    if ( stuff->full&XkbKeySymsMask ) {
	rep.firstKeySym = xkb->min_key_code;
	rep.nKeySyms = n;
    }
    else if (stuff->partial&XkbKeySymsMask) {
	CHK_KEY_RANGE(0x05,stuff->firstKeySym,stuff->nKeySyms,xkb);
	rep.firstKeySym = stuff->firstKeySym;
	rep.nKeySyms = stuff->nKeySyms;
    }
    else rep.nKeySyms = 0;
    rep.totalSyms= 0;

    if ( stuff->full&XkbKeyActionsMask ) {
	rep.firstKeyAct= xkb->min_key_code;
	rep.nKeyActs= n;
    }
    else if (stuff->partial&XkbKeyActionsMask) {
	CHK_KEY_RANGE(0x07,stuff->firstKeyAct,stuff->nKeyActs,xkb);
	rep.firstKeyAct= stuff->firstKeyAct;
	rep.nKeyActs= stuff->nKeyActs;
    }
    else rep.nKeyActs= 0;
    rep.totalActs= 0;

    if ( stuff->full&XkbKeyBehaviorsMask ) {
	rep.firstKeyBehavior = xkb->min_key_code;
	rep.nKeyBehaviors = n;
    }
    else if (stuff->partial&XkbKeyBehaviorsMask) {
	CHK_KEY_RANGE(0x09,stuff->firstKeyBehavior,stuff->nKeyBehaviors,xkb);
	rep.firstKeyBehavior= stuff->firstKeyBehavior;
	rep.nKeyBehaviors= stuff->nKeyBehaviors;
    }
    else rep.nKeyBehaviors = 0;
    rep.totalKeyBehaviors= 0;

    if (stuff->full&XkbVirtualModsMask)
	rep.virtualMods= ~0;
    else if (stuff->partial&XkbVirtualModsMask)
	rep.virtualMods= stuff->virtualMods;

    if (stuff->full&XkbExplicitComponentsMask) {
	rep.firstKeyExplicit= xkb->min_key_code;
	rep.nKeyExplicit= n;
    }
    else if (stuff->partial&XkbExplicitComponentsMask) {
	CHK_KEY_RANGE(0x0B,stuff->firstKeyExplicit,stuff->nKeyExplicit,xkb);
	rep.firstKeyExplicit= stuff->firstKeyExplicit;
	rep.nKeyExplicit= stuff->nKeyExplicit;
    }
    else rep.nKeyExplicit = 0;
    rep.totalKeyExplicit=  0;

    if (stuff->full&XkbModifierMapMask) {
	rep.firstModMapKey= xkb->min_key_code;
	rep.nModMapKeys= n;
    }
    else if (stuff->partial&XkbModifierMapMask) {
	CHK_KEY_RANGE(0x0D,stuff->firstModMapKey,stuff->nModMapKeys,xkb);
	rep.firstModMapKey= stuff->firstModMapKey;
	rep.nModMapKeys= stuff->nModMapKeys;
    }
    else rep.nModMapKeys = 0;
    rep.totalModMapKeys= 0;

    if (stuff->full&XkbVirtualModMapMask) {
	rep.firstVModMapKey= xkb->min_key_code;
	rep.nVModMapKeys= n;
    }
    else if (stuff->partial&XkbVirtualModMapMask) {
	CHK_KEY_RANGE(0x0F,stuff->firstVModMapKey,stuff->nVModMapKeys,xkb);
	rep.firstVModMapKey= stuff->firstVModMapKey;
	rep.nVModMapKeys= stuff->nVModMapKeys;
    }
    else rep.nVModMapKeys = 0;
    rep.totalVModMapKeys= 0;

    if ((status=XkbComputeGetMapReplySize(xkb,&rep))!=Success)
	return status;
    return XkbSendMap(client,xkb,&rep);
}


_XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq *req, char* values)
{
    XkbSrvInfoPtr       xkbi;
    XkbDescPtr          xkb;
    int                 error;
    int                 nTypes = 0, nActions;
    CARD8               mapWidths[XkbMaxLegalKeyCode + 1];
    CARD16              symsPerKey[XkbMaxLegalKeyCode + 1];

    xkbi= dev->key->xkbInfo;
    xkb = xkbi->desc;

    if ((xkb->min_key_code != req->minKeyCode)||
        (xkb->max_key_code != req->maxKeyCode)) {
	if (client->vMajor!=1) { /* pre 1.0 versions of Xlib have a bug */
	    req->minKeyCode= xkb->min_key_code;
	    req->maxKeyCode= xkb->max_key_code;
	}
	else {
	    if (!XkbIsLegalKeycode(req->minKeyCode)) {
		client->errorValue = _XkbErrCode3(2, req->minKeyCode, req->maxKeyCode);
		return BadValue;
	    }
	    if (req->minKeyCode > req->maxKeyCode) {
		client->errorValue = _XkbErrCode3(3, req->minKeyCode, req->maxKeyCode);
		return BadMatch;
	    }
	}
    }

    if ((req->present & XkbKeyTypesMask) &&
	(!CheckKeyTypes(client,xkb,req,(xkbKeyTypeWireDesc **)&values,
						&nTypes,mapWidths))) {
	client->errorValue = nTypes;
	return BadValue;
    }
    if ((req->present & XkbKeySymsMask) &&
	(!CheckKeySyms(client,xkb,req,nTypes,mapWidths,symsPerKey,
					(xkbSymMapWireDesc **)&values,&error))) {
	client->errorValue = error;
	return BadValue;
    }

    if ((req->present & XkbKeyActionsMask) &&
	(!CheckKeyActions(xkb,req,nTypes,mapWidths,symsPerKey,
						(CARD8 **)&values,&nActions))) {
	client->errorValue = nActions;
	return BadValue;
    }

    if ((req->present & XkbKeyBehaviorsMask) &&
	(!CheckKeyBehaviors(xkb,req,(xkbBehaviorWireDesc**)&values,&error))) {
	client->errorValue = error;
	return BadValue;
    }

    if ((req->present & XkbVirtualModsMask) &&
	(!CheckVirtualMods(xkb,req,(CARD8 **)&values,&error))) {
	client->errorValue= error;
	return BadValue;
    }
    if ((req->present&XkbExplicitComponentsMask) &&
	(!CheckKeyExplicit(xkb,req,(CARD8 **)&values,&error))) {
	client->errorValue= error;
	return BadValue;
    }
    if ((req->present&XkbModifierMapMask) &&
	(!CheckModifierMap(xkb,req,(CARD8 **)&values,&error))) {
	client->errorValue= error;
	return BadValue;
    }
    if ((req->present&XkbVirtualModMapMask) &&
	(!CheckVirtualModMap(xkb,req,(xkbVModMapWireDesc **)&values,&error))) {
	client->errorValue= error;
	return BadValue;
    }

    if (((values-((char *)req))/4)!= req->length) {
	ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after check)\n");
	client->errorValue = values-((char *)&req[1]);
	return BadLength;
    }

    return Success;
}


_GetCountedString(char **wire_inout,Bool swap)
{
char *	wire,*str;
CARD16	len,*plen;

    wire= *wire_inout;
    plen= (CARD16 *)wire;
    if (swap) {
	register int n;
	swaps(plen,n);
    }
    len= *plen;
    str= (char *)_XkbAlloc(len+1);
    if (str) {
	memcpy(str,&wire[2],len);
	str[len]= '\0';
    }
    wire+= XkbPaddedSize(len+2);
    *wire_inout= wire;
    return str;
}


XkbSizeGeomShapes(XkbGeometryPtr geom)
{
register int		i,size;
register XkbShapePtr	shape;

    for (i=size=0,shape=geom->shapes;i<geom->num_shapes;i++,shape++) {
	register int		n;
	register XkbOutlinePtr	ol;
	size+= SIZEOF(xkbShapeWireDesc);
	for (n=0,ol=shape->outlines;n<shape->num_outlines;n++,ol++) {
	    size+= SIZEOF(xkbOutlineWireDesc);
	    size+= ol->num_points*SIZEOF(xkbPointWireDesc);
	}
    }
    return size;
}


SendDeviceLedFBs(	DeviceIntPtr	dev,
			int		class,
			int		id,
			unsigned	wantLength,
			ClientPtr	client)
{
int			length= 0;

    if (class==XkbDfltXIClass) {
	if (dev->kbdfeed)	class= KbdFeedbackClass;
	else if (dev->leds)	class= LedFeedbackClass;
    }
    if ((dev->kbdfeed)&&
	((class==KbdFeedbackClass)||(class==XkbAllXIClasses))) {
	KbdFeedbackPtr kf;
	for (kf= dev->kbdfeed;(kf);kf=kf->next) {
	    if ((id==XkbAllXIIds)||(id==XkbDfltXIId)||(id==kf->ctrl.id)) {
		length+= SendDeviceLedInfo(kf->xkb_sli,client);
		if (id!=XkbAllXIIds)
		    break;
	    }
	}
    }
    if ((dev->leds)&&
	((class==LedFeedbackClass)||(class==XkbAllXIClasses))) {
	LedFeedbackPtr lf;
	for (lf= dev->leds;(lf);lf=lf->next) {
	    if ((id==XkbAllXIIds)||(id==XkbDfltXIId)||(id==lf->ctrl.id)) {
		length+= SendDeviceLedInfo(lf->xkb_sli,client);
		if (id!=XkbAllXIIds)
		    break;
	    }
	}
    }
    if (length==wantLength)
	 return Success;
    else return BadLength;
}


XkbSendGeometry(	ClientPtr		client,
			XkbGeometryPtr		geom,
			xkbGetGeometryReply *	rep,
			Bool			freeGeom)
{
    char	*desc,*start;
    int		 len;

    if (geom!=NULL) {
	len= rep->length*4;
	start= desc= (char *)xalloc(len);
	if (!start)
	    return BadAlloc;
	desc=  XkbWriteCountedString(desc,geom->label_font,client->swapped);
	if ( rep->nProperties>0 )
	    desc = XkbWriteGeomProperties(desc,geom,client->swapped);
	if ( rep->nColors>0 )
	    desc = XkbWriteGeomColors(desc,geom,client->swapped);
	if ( rep->nShapes>0 )
	    desc = XkbWriteGeomShapes(desc,geom,client->swapped);
	if ( rep->nSections>0 )
	    desc = XkbWriteGeomSections(desc,geom,client->swapped);
	if ( rep->nDoodads>0 )
	    desc = XkbWriteGeomDoodads(desc,geom->num_doodads,geom->doodads,
							  client->swapped);
	if ( rep->nKeyAliases>0 )
	    desc = XkbWriteGeomKeyAliases(desc,geom,client->swapped);
	if ((desc-start)!=(len)) {
	    ErrorF("[xkb] BOGUS LENGTH in XkbSendGeometry, expected %d, got %ld\n",
			len, (unsigned long)(desc-start));
	}
    }
    else {
	len= 0;
	start= NULL;
    }
    if (client->swapped) {
	register int n;
	swaps(&rep->sequenceNumber,n);
	swapl(&rep->length,n);
	swapl(&rep->name,n);
	swaps(&rep->widthMM,n);
	swaps(&rep->heightMM,n);
	swaps(&rep->nProperties,n);
	swaps(&rep->nColors,n);
	swaps(&rep->nShapes,n);
	swaps(&rep->nSections,n);
	swaps(&rep->nDoodads,n);
	swaps(&rep->nKeyAliases,n);
    }
    WriteToClient(client, SIZEOF(xkbGetGeometryReply), (char *)rep);
    if (len>0)
	WriteToClient(client, len, start);
    if (start!=NULL)
	xfree((char *)start);
    if (freeGeom)
	XkbFreeGeometry(geom,XkbGeomAllMask,True);
    return client->noClientException;
}


CheckModifierMap(XkbDescPtr xkb,xkbSetMapReq *req,CARD8 **wireRtrn,int *errRtrn)
{
register CARD8 *	wire = *wireRtrn;
CARD8	*		start;
register unsigned 	i;
int			first,last;

    if (((req->present&XkbModifierMapMask)==0)||(req->nModMapKeys<1)) {
	req->present&= ~XkbModifierMapMask;
	req->nModMapKeys= 0;
	return 1;
    }
    first= req->firstModMapKey;
    last=  first+req->nModMapKeys-1;
    if (first<req->minKeyCode) {
	*errRtrn = _XkbErrCode3(0x61,first,req->minKeyCode);
	return 0;
    }
    if (last>req->maxKeyCode) {
	*errRtrn = _XkbErrCode3(0x62,last,req->maxKeyCode);
	return 0;
    }
    start= wire;
    for (i=0;i<req->totalModMapKeys;i++,wire+=2) {
	if ((wire[0]<first)||(wire[0]>last)) {
	    *errRtrn = _XkbErrCode4(0x63,first,last,wire[0]);
	    return 0;
	}
    }
    wire+= XkbPaddedSize(wire-start)-(wire-start);
    *wireRtrn= wire;
    return 1;
}


XkbComputeGetGeometryReplySize(	XkbGeometryPtr		geom,
				xkbGetGeometryReply *	rep,
				Atom			name)
{
int	len;

    if (geom!=NULL) {
	len= XkbSizeCountedString(geom->label_font);
	len+= XkbSizeGeomProperties(geom);
	len+= XkbSizeGeomColors(geom);
	len+= XkbSizeGeomShapes(geom);
	len+= XkbSizeGeomSections(geom);
	len+= XkbSizeGeomDoodads(geom->num_doodads,geom->doodads);
	len+= XkbSizeGeomKeyAliases(geom);
	rep->length= len/4;
	rep->found= True;
	rep->name= geom->name;
	rep->widthMM= geom->width_mm;
	rep->heightMM= geom->height_mm;
	rep->nProperties= geom->num_properties;
	rep->nColors= geom->num_colors;
	rep->nShapes= geom->num_shapes;
	rep->nSections= geom->num_sections;
	rep->nDoodads= geom->num_doodads;
	rep->nKeyAliases= geom->num_key_aliases;
	rep->baseColorNdx= XkbGeomColorIndex(geom,geom->base_color);
	rep->labelColorNdx= XkbGeomColorIndex(geom,geom->label_color);
    }
    else {
	rep->length= 0;
	rep->found= False;
	rep->name= name;
	rep->widthMM= rep->heightMM= 0;
	rep->nProperties= rep->nColors= rep->nShapes= 0;
	rep->nSections= rep->nDoodads= 0;
	rep->nKeyAliases= 0;
	rep->labelColorNdx= rep->baseColorNdx= 0;
    }
    return Success;
}


ProcXkbGetCompatMap(ClientPtr client)
{
    xkbGetCompatMapReply 	rep;
    DeviceIntPtr 		dev;
    XkbDescPtr			xkb;
    XkbCompatMapPtr		compat;

    REQUEST(xkbGetCompatMapReq);
    REQUEST_SIZE_MATCH(xkbGetCompatMapReq);

    if (!(client->xkbClientFlags&_XkbClientInitialized))
	return BadAccess;

    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);

    xkb = dev->key->xkbInfo->desc;
    compat= xkb->compat;

    rep.type = X_Reply;
    rep.deviceID = dev->id;
    rep.sequenceNumber = client->sequence;
    rep.length = 0;
    rep.firstSI = stuff->firstSI;
    rep.nSI = stuff->nSI;
    if (stuff->getAllSI) {
	rep.firstSI = 0;
	rep.nSI = compat->num_si;
    }
    else if ((((unsigned)stuff->nSI)>0)&&
		((unsigned)(stuff->firstSI+stuff->nSI-1)>=compat->num_si)) {
	client->errorValue = _XkbErrCode2(0x05,compat->num_si);
	return BadValue;
    }
    rep.nTotalSI = compat->num_si;
    rep.groups= stuff->groups;
    XkbComputeGetCompatMapReplySize(compat,&rep);
    return XkbSendCompatMap(client,compat,&rep);
}


_XkbSetNamesCheck(ClientPtr client, DeviceIntPtr dev,
                  xkbSetNamesReq *stuff, CARD32 *data)
{
    XkbDescRec		*xkb;
    XkbNamesRec		*names;
    CARD32		*tmp;
    Atom		 bad;

    tmp = data;
    xkb = dev->key->xkbInfo->desc;
    names = xkb->names;

    if (stuff->which & XkbKeyTypeNamesMask) {
        int i;
        CARD32	*old;
        if ( stuff->nTypes<1 ) {
            client->errorValue = _XkbErrCode2(0x02,stuff->nTypes);
            return BadValue;
        }
        if ((unsigned)(stuff->firstType+stuff->nTypes-1)>=xkb->map->num_types) {
            client->errorValue = _XkbErrCode4(0x03,stuff->firstType,
                    stuff->nTypes,
                    xkb->map->num_types);
            return BadValue;
        }
        if (((unsigned)stuff->firstType)<=XkbLastRequiredType) {
            client->errorValue = _XkbErrCode2(0x04,stuff->firstType);
            return BadAccess;
        }
        old= tmp;
        tmp= _XkbCheckAtoms(tmp,stuff->nTypes,client->swapped,&bad);
        if (!tmp) {
            client->errorValue= bad;
            return BadAtom;
        }
        for (i=0;i<stuff->nTypes;i++,old++) {
            if (!_XkbCheckTypeName((Atom)*old,stuff->firstType+i))
                client->errorValue= _XkbErrCode2(0x05,i);
        }
    }
    if (stuff->which&XkbKTLevelNamesMask) {
        unsigned i;
        XkbKeyTypePtr	type;
        CARD8 *		width;
        if ( stuff->nKTLevels<1 ) {
            client->errorValue = _XkbErrCode2(0x05,stuff->nKTLevels);
            return BadValue;
        }
        if ((unsigned)(stuff->firstKTLevel+stuff->nKTLevels-1)>=
                xkb->map->num_types) {
            client->errorValue = _XkbErrCode4(0x06,stuff->firstKTLevel,
                    stuff->nKTLevels,xkb->map->num_types);
            return BadValue;
        }
        width = (CARD8 *)tmp;
        tmp= (CARD32 *)(((char *)tmp)+XkbPaddedSize(stuff->nKTLevels));
        type = &xkb->map->types[stuff->firstKTLevel];
        for (i=0;i<stuff->nKTLevels;i++,type++) {
            if (width[i]==0)
                continue;
            else if (width[i]!=type->num_levels) {
                client->errorValue= _XkbErrCode4(0x07,i+stuff->firstKTLevel,
                        type->num_levels,width[i]);
                return BadMatch;
            }
            tmp= _XkbCheckAtoms(tmp,width[i],client->swapped,&bad);
            if (!tmp) {
                client->errorValue= bad;
                return BadAtom;
            }
        }
    }
    if (stuff->which&XkbIndicatorNamesMask) {
        if (stuff->indicators==0) {
            client->errorValue= 0x08;
            return BadMatch;
        }
        tmp= _XkbCheckMaskedAtoms(tmp,XkbNumIndicators,stuff->indicators,
                client->swapped,&bad);
        if (!tmp) {
            client->errorValue= bad;
            return BadAtom;
        }
    }
    if (stuff->which&XkbVirtualModNamesMask) {
        if (stuff->virtualMods==0) {
            client->errorValue= 0x09;
            return BadMatch;
        }
        tmp= _XkbCheckMaskedAtoms(tmp,XkbNumVirtualMods,
                (CARD32)stuff->virtualMods,
                client->swapped,&bad);
        if (!tmp) {
            client->errorValue = bad;
            return BadAtom;
        }
    }
    if (stuff->which&XkbGroupNamesMask) {
        if (stuff->groupNames==0) {
            client->errorValue= 0x0a;
            return BadMatch;
        }
        tmp= _XkbCheckMaskedAtoms(tmp,XkbNumKbdGroups,
                (CARD32)stuff->groupNames,
                client->swapped,&bad);
        if (!tmp) {
            client->errorValue = bad;
            return BadAtom;
        }
    }
    if (stuff->which&XkbKeyNamesMask) {
        if (stuff->firstKey<(unsigned)xkb->min_key_code) {
            client->errorValue= _XkbErrCode3(0x0b,xkb->min_key_code,
                    stuff->firstKey);
            return BadValue;
        }
        if (((unsigned)(stuff->firstKey+stuff->nKeys-1)>xkb->max_key_code)||
                (stuff->nKeys<1)) {
            client->errorValue= _XkbErrCode4(0x0c,xkb->max_key_code,
                    stuff->firstKey,stuff->nKeys);
            return BadValue;
        }
        tmp+= stuff->nKeys;
    }
    if ((stuff->which&XkbKeyAliasesMask)&&(stuff->nKeyAliases>0)) {
        tmp+= stuff->nKeyAliases*2;
    }
    if (stuff->which&XkbRGNamesMask) {
        if ( stuff->nRadioGroups<1 ) {
            client->errorValue= _XkbErrCode2(0x0d,stuff->nRadioGroups);
            return BadValue;
        }
        tmp= _XkbCheckAtoms(tmp,stuff->nRadioGroups,client->swapped,&bad);
        if (!tmp) {
            client->errorValue= bad;
            return BadAtom;
        }
    }
    if ((tmp-((CARD32 *)stuff))!=stuff->length) {
        client->errorValue = stuff->length;
        return BadLength;
    }

    return Success;
}


_CheckSetGeom(	XkbGeometryPtr		geom,
		xkbSetGeometryReq *	req,
		ClientPtr 		client)
{
register int	i;
Status		status;
char *		wire;

    wire= (char *)&req[1];
    geom->label_font= _GetCountedString(&wire,client->swapped);

    for (i=0;i<req->nProperties;i++) {
	char *name,*val;
	name= _GetCountedString(&wire,client->swapped);
        if (!name)
            return BadAlloc;
	val= _GetCountedString(&wire,client->swapped);
        if (!val) {
            xfree(name);
            return BadAlloc;
        }
	if (XkbAddGeomProperty(geom,name,val)==NULL) {
            xfree(name);
            xfree(val);
	    return BadAlloc;
        }
        xfree(name);
        xfree(val);
    }

    if (req->nColors<2) {
	client->errorValue= _XkbErrCode3(0x01,2,req->nColors);
	return BadValue;
    }
    if (req->baseColorNdx>req->nColors) {
	client->errorValue=_XkbErrCode3(0x03,req->nColors,req->baseColorNdx);
	return BadMatch;
    }
    if (req->labelColorNdx>req->nColors) {
	client->errorValue= _XkbErrCode3(0x03,req->nColors,req->labelColorNdx);
	return BadMatch;
    }
    if (req->labelColorNdx==req->baseColorNdx) {
	client->errorValue= _XkbErrCode3(0x04,req->baseColorNdx,
                                         req->labelColorNdx);
	return BadMatch;
    }

    for (i=0;i<req->nColors;i++) {
	char *name;
	name= _GetCountedString(&wire,client->swapped);
	if (!name)
            return BadAlloc;
        if (!XkbAddGeomColor(geom,name,geom->num_colors)) {
            xfree(name);
	    return BadAlloc;
        }
        xfree(name);
    }
    if (req->nColors!=geom->num_colors) {
	client->errorValue= _XkbErrCode3(0x05,req->nColors,geom->num_colors);
	return BadMatch;
    }
    geom->label_color= &geom->colors[req->labelColorNdx];
    geom->base_color= &geom->colors[req->baseColorNdx];

    if ((status=_CheckSetShapes(geom,req,&wire,client))!=Success)
	return status;

    if ((status=_CheckSetSections(geom,req,&wire,client))!=Success)
	return status;

    for (i=0;i<req->nDoodads;i++) {
	status=_CheckSetDoodad(&wire,geom,NULL,client);
	if (status!=Success)
	    return status;
    }

    for (i=0;i<req->nKeyAliases;i++) {
	if (XkbAddGeomKeyAlias(geom,&wire[XkbKeyNameLength],wire)==NULL)
	    return BadAlloc;
	wire+= 2*XkbKeyNameLength;
    }
    return Success;
}


_XkbFindNamedIndicatorMap(XkbSrvLedInfoPtr sli, Atom indicator,
                          int *led_return)
{
    XkbIndicatorMapPtr  map;
    int                 led;

    /* search for the right indicator */
    map = NULL;
    if (sli->names && sli->maps) {
	for (led = 0; (led < XkbNumIndicators) && (map == NULL); led++) {
	    if (sli->names[led] == indicator) {
		map= &sli->maps[led];
		break;
	    }
	}
    }

    *led_return = led;
    return map;
}


ProcXkbLatchLockState(ClientPtr client)
{
    int status;
    DeviceIntPtr dev, tmpd;
    XkbStateRec	oldState,*newState;
    CARD16 changed;
    xkbStateNotify sn;
    XkbEventCauseRec cause;

    REQUEST(xkbLatchLockStateReq);
    REQUEST_SIZE_MATCH(xkbLatchLockStateReq);

    if (!(client->xkbClientFlags & _XkbClientInitialized))
	return BadAccess;

    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess);
    CHK_MASK_MATCH(0x01, stuff->affectModLocks, stuff->modLocks);
    CHK_MASK_MATCH(0x01, stuff->affectModLatches, stuff->modLatches);

    status = Success;

    for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) {
        if ((dev == inputInfo.keyboard && tmpd->key && tmpd->coreEvents) ||
            tmpd == dev) {
            if (!tmpd->key->xkbInfo)
                continue;

            oldState = tmpd->key->xkbInfo->state;
            newState = &tmpd->key->xkbInfo->state;
            if (stuff->affectModLocks) {
                newState->locked_mods &= ~stuff->affectModLocks;
                newState->locked_mods |= (stuff->affectModLocks & stuff->modLocks);
            }
            if (status == Success && stuff->lockGroup)
                newState->locked_group = stuff->groupLock;
            if (status == Success && stuff->affectModLatches)
                status = XkbLatchModifiers(tmpd, stuff->affectModLatches,
                                           stuff->modLatches);
            if (status == Success && stuff->latchGroup)
                status = XkbLatchGroup(tmpd, stuff->groupLatch);

            if (status != Success)
                return status;

            XkbComputeDerivedState(tmpd->key->xkbInfo);
            tmpd->key->state = XkbStateFieldFromRec(newState);

            changed = XkbStateChangedFlags(&oldState, newState);
            if (changed) {
                sn.keycode = 0;
                sn.eventType = 0;
                sn.requestMajor = XkbReqCode;
                sn.requestMinor = X_kbLatchLockState;
                sn.changed = changed;
                XkbSendStateNotify(tmpd, &sn);
                changed = XkbIndicatorsToUpdate(tmpd, changed, False);
                if (changed) {
                    XkbSetCauseXkbReq(&cause, X_kbLatchLockState, client);
                    XkbUpdateIndicators(tmpd, changed, True, NULL, &cause);
	        }
            }
        }
    }

    return client->noClientException;
}


_XkbCheckAtoms(CARD32 *wire,int nAtoms,int swapped,Atom *pError)
{
register int i;

    for (i=0;i<nAtoms;i++,wire++) {
	if (swapped) {
	    register int n;
	    swapl(wire,n);
	}
	if ((((Atom)*wire)!=None)&&(!ValidAtom((Atom)*wire))) {
	    *pError= ((Atom)*wire);
	    return NULL;
	}
    }
    return wire;
}