xkmread.c revision 4642e01f
1/************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32
33#include <X11/Xos.h>
34#include <X11/Xfuncs.h>
35
36#include <X11/X.h>
37#define	NEED_EVENTS
38#include <X11/Xproto.h>
39#include <X11/keysym.h>
40#include "misc.h"
41#include "inputstr.h"
42#include "xkbstr.h"
43#include "xkbsrv.h"
44#include "xkbgeom.h"
45
46Atom
47XkbInternAtom(char *str,Bool only_if_exists)
48{
49    if (str==NULL)
50	return None;
51    return MakeAtom(str,strlen(str),!only_if_exists);
52}
53
54char *
55_XkbDupString(char *str)
56{
57char *new;
58
59   if (str==NULL)
60	return NULL;
61   new= (char *)_XkbCalloc(strlen(str)+1,sizeof(char));
62   if (new)
63	strcpy(new,str);
64   return new;
65}
66
67/***====================================================================***/
68
69static void *
70XkmInsureSize(void *oldPtr,int oldCount,int *newCountRtrn,int elemSize)
71{
72int	newCount= *newCountRtrn;
73
74    if (oldPtr==NULL) {
75	if (newCount==0)
76	    return NULL;
77	oldPtr= _XkbCalloc(newCount,elemSize);
78    }
79    else if (oldCount<newCount) {
80	oldPtr= _XkbRealloc(oldPtr,newCount*elemSize);
81	if (oldPtr!=NULL) {
82	    char *tmp= (char *)oldPtr;
83	    bzero(&tmp[oldCount*elemSize],(newCount-oldCount)*elemSize);
84	}
85    }
86    else if (newCount<oldCount) {
87	*newCountRtrn= oldCount;
88    }
89    return oldPtr;
90}
91
92#define	XkmInsureTypedSize(p,o,n,t) ((p)=((t *)XkmInsureSize((char *)(p),(o),(n),sizeof(t))))
93
94static CARD8
95XkmGetCARD8(FILE *file,int *pNRead)
96{
97int	tmp;
98    tmp= getc(file);
99    if (pNRead&&(tmp!=EOF))
100	(*pNRead)+= 1;
101    return tmp;
102}
103
104static CARD16
105XkmGetCARD16(FILE *file,int *pNRead)
106{
107CARD16		val;
108
109    if ((fread(&val,2,1,file)==1)&&(pNRead))
110	(*pNRead)+= 2;
111    return val;
112}
113
114static CARD32
115XkmGetCARD32(FILE *file,int *pNRead)
116{
117CARD32	val;
118
119    if ((fread(&val,4,1,file)==1)&&(pNRead))
120	(*pNRead)+= 4;
121    return val;
122}
123
124static int
125XkmSkipPadding(FILE *file,unsigned pad)
126{
127register int	i,nRead=0;
128
129    for (i=0;i<pad;i++) {
130	if (getc(file)!=EOF)
131	    nRead++;
132    }
133    return nRead;
134}
135
136static int
137XkmGetCountedString(FILE *file,char *str,int max_len)
138{
139int	count,nRead=0;
140
141    count= XkmGetCARD16(file,&nRead);
142    if (count>0) {
143	int tmp;
144	if (count>max_len) {
145	    tmp= fread(str,1,max_len,file);
146	    while (tmp<count) {
147		if ((getc(file))!=EOF)
148		     tmp++;
149		else break;
150	    }
151	}
152	else {
153	    tmp= fread(str,1,count,file);
154	}
155	nRead+= tmp;
156    }
157    if (count>=max_len)	str[max_len-1]= '\0';
158    else		str[count]= '\0';
159    count= XkbPaddedSize(nRead)-nRead;
160    if (count>0)
161	nRead+= XkmSkipPadding(file,count);
162    return nRead;
163}
164
165/***====================================================================***/
166
167static int
168ReadXkmVirtualMods(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
169{
170register unsigned int i,bit;
171unsigned int	bound,named,tmp;
172int		nRead=0;
173
174    if (XkbAllocServerMap(xkb,XkbVirtualModsMask,0)!=Success) {
175	_XkbLibError(_XkbErrBadAlloc,"ReadXkmVirtualMods",0);
176	return -1;
177    }
178    bound= XkmGetCARD16(file,&nRead);
179    named= XkmGetCARD16(file,&nRead);
180    for (i=tmp=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
181	if (bound&bit) {
182	    xkb->server->vmods[i]= XkmGetCARD8(file,&nRead);
183	    if (changes)
184		changes->map.vmods|= bit;
185	    tmp++;
186	}
187    }
188    if ((i= XkbPaddedSize(tmp)-tmp)>0)
189	nRead+= XkmSkipPadding(file,i);
190    if (XkbAllocNames(xkb,XkbVirtualModNamesMask,0,0)!=Success) {
191	_XkbLibError(_XkbErrBadAlloc,"ReadXkmVirtualMods",0);
192	return -1;
193    }
194    for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
195	char name[100];
196	if (named&bit) {
197	    if (nRead+=XkmGetCountedString(file,name,100)) {
198		xkb->names->vmods[i]= XkbInternAtom(name,False);
199		if (changes)
200		    changes->names.changed_vmods|= bit;
201	    }
202	}
203    }
204    return nRead;
205}
206
207/***====================================================================***/
208
209static int
210ReadXkmKeycodes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
211{
212register int	i;
213unsigned	minKC,maxKC,nAl;
214int		nRead=0;
215char 		name[100];
216XkbKeyNamePtr	pN;
217
218    name[0]= '\0';
219    nRead+= XkmGetCountedString(file,name,100);
220    minKC= XkmGetCARD8(file,&nRead);
221    maxKC= XkmGetCARD8(file,&nRead);
222    if (xkb->min_key_code==0) {
223	xkb->min_key_code= minKC;
224	xkb->max_key_code= maxKC;
225    }
226    else {
227	if (minKC<xkb->min_key_code)
228	    xkb->min_key_code= minKC;
229	if (maxKC>xkb->max_key_code) {
230	    _XkbLibError(_XkbErrBadValue,"ReadXkmKeycodes",maxKC);
231	    return -1;
232	}
233    }
234    nAl= XkmGetCARD8(file,&nRead);
235    nRead+= XkmSkipPadding(file,1);
236
237#define WANTED (XkbKeycodesNameMask|XkbKeyNamesMask|XkbKeyAliasesMask)
238    if (XkbAllocNames(xkb,WANTED,0,nAl)!=Success) {
239	_XkbLibError(_XkbErrBadAlloc,"ReadXkmKeycodes",0);
240	return -1;
241    }
242    if (name[0]!='\0') {
243	xkb->names->keycodes= XkbInternAtom(name,False);
244    }
245
246    for (pN=&xkb->names->keys[minKC],i=minKC;i<=(int)maxKC;i++,pN++) {
247	if (fread(pN,1,XkbKeyNameLength,file)!=XkbKeyNameLength) {
248	    _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0);
249	    return -1;
250	}
251	nRead+= XkbKeyNameLength;
252    }
253    if (nAl>0) {
254	XkbKeyAliasPtr	pAl;
255	for (pAl= xkb->names->key_aliases,i=0;i<nAl;i++,pAl++) {
256	    int tmp;
257	    tmp= fread(pAl,1,2*XkbKeyNameLength,file);
258	    if (tmp!=2*XkbKeyNameLength) {
259		_XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0);
260		return -1;
261	    }
262	    nRead+= 2*XkbKeyNameLength;
263	}
264	if (changes)
265	    changes->names.changed|= XkbKeyAliasesMask;
266    }
267    if (changes)
268	changes->names.changed|= XkbKeyNamesMask;
269    return nRead;
270}
271
272/***====================================================================***/
273
274static int
275ReadXkmKeyTypes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
276{
277register unsigned	i,n;
278unsigned		num_types;
279int			nRead=0;
280int			tmp;
281XkbKeyTypePtr		type;
282xkmKeyTypeDesc		wire;
283XkbKTMapEntryPtr	entry;
284xkmKTMapEntryDesc	wire_entry;
285char 			buf[100];
286
287    if ((tmp= XkmGetCountedString(file,buf,100))<1) {
288	_XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0);
289	return -1;
290    }
291    nRead+= tmp;
292    if (buf[0]!='\0') {
293	if (XkbAllocNames(xkb,XkbTypesNameMask,0,0)!=Success) {
294	    _XkbLibError(_XkbErrBadAlloc,"ReadXkmKeyTypes",0);
295	    return -1;
296        }
297	xkb->names->types= XkbInternAtom(buf,False);
298    }
299    num_types= XkmGetCARD16(file,&nRead);
300    nRead+= XkmSkipPadding(file,2);
301    if (num_types<1)
302	return nRead;
303    if (XkbAllocClientMap(xkb,XkbKeyTypesMask,num_types)!=Success) {
304	_XkbLibError(_XkbErrBadAlloc,"ReadXkmKeyTypes",0);
305	return nRead;
306    }
307    xkb->map->num_types= num_types;
308    if (num_types<XkbNumRequiredTypes) {
309	_XkbLibError(_XkbErrMissingReqTypes,"ReadXkmKeyTypes",0);
310	return -1;
311    }
312    type= xkb->map->types;
313    for (i=0;i<num_types;i++,type++) {
314	if ((int)fread(&wire,SIZEOF(xkmKeyTypeDesc),1,file)<1) {
315	    _XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0);
316	    return -1;
317	}
318	nRead+= SIZEOF(xkmKeyTypeDesc);
319	if (((i==XkbOneLevelIndex)&&(wire.numLevels!=1))||
320	    (((i==XkbTwoLevelIndex)||(i==XkbAlphabeticIndex)||
321	     ((i)==XkbKeypadIndex))&&(wire.numLevels!=2))) {
322	    _XkbLibError(_XkbErrBadTypeWidth,"ReadXkmKeyTypes",i);
323	    return -1;
324	}
325	tmp= wire.nMapEntries;
326	XkmInsureTypedSize(type->map,type->map_count,&tmp,XkbKTMapEntryRec);
327	if ((wire.nMapEntries>0)&&(type->map==NULL)) {
328	    _XkbLibError(_XkbErrBadValue,"ReadXkmKeyTypes",wire.nMapEntries);
329	    return -1;
330	}
331	for (n=0,entry= type->map;n<wire.nMapEntries;n++,entry++) {
332	    if (fread(&wire_entry,SIZEOF(xkmKTMapEntryDesc),1,file)<(int)1) {
333		_XkbLibError(_XkbErrBadLength,"ReadXkmKeyTypes",0);
334		return -1;
335	    }
336	    nRead+= SIZEOF(xkmKTMapEntryDesc);
337	    entry->active= (wire_entry.virtualMods==0);
338	    entry->level= wire_entry.level;
339	    entry->mods.mask= wire_entry.realMods;
340	    entry->mods.real_mods= wire_entry.realMods;
341	    entry->mods.vmods= wire_entry.virtualMods;
342	}
343	nRead+= XkmGetCountedString(file,buf,100);
344	if (((i==XkbOneLevelIndex)&&(strcmp(buf,"ONE_LEVEL")!=0))||
345	    ((i==XkbTwoLevelIndex)&&(strcmp(buf,"TWO_LEVEL")!=0))||
346	    ((i==XkbAlphabeticIndex)&&(strcmp(buf,"ALPHABETIC")!=0))||
347	    ((i==XkbKeypadIndex)&&(strcmp(buf,"KEYPAD")!=0))) {
348	   _XkbLibError(_XkbErrBadTypeName,"ReadXkmKeyTypes",0);
349	   return -1;
350	}
351	if (buf[0]!='\0') {
352	     type->name= XkbInternAtom(buf,False);
353	}
354	else type->name= None;
355
356	if (wire.preserve) {
357	    xkmModsDesc	p_entry;
358	    XkbModsPtr	pre;
359	    XkmInsureTypedSize(type->preserve,type->map_count,&tmp,
360						XkbModsRec);
361	    if (type->preserve==NULL) {
362		_XkbLibError(_XkbErrBadMatch,"ReadXkmKeycodes",0);
363		return -1;
364	    }
365	    for (n=0,pre=type->preserve;n<wire.nMapEntries;n++,pre++) {
366		if (fread(&p_entry,SIZEOF(xkmModsDesc),1,file)<1) {
367		    _XkbLibError(_XkbErrBadLength,"ReadXkmKeycodes",0);
368		    return -1;
369		}
370		nRead+= SIZEOF(xkmModsDesc);
371		pre->mask= p_entry.realMods;
372		pre->real_mods= p_entry.realMods;
373		pre->vmods= p_entry.virtualMods;
374	    }
375	}
376	if (wire.nLevelNames>0) {
377	    int width= wire.numLevels;
378	    if (wire.nLevelNames>(unsigned)width) {
379		_XkbLibError(_XkbErrBadMatch,"ReadXkmKeycodes",0);
380		return -1;
381	    }
382	    XkmInsureTypedSize(type->level_names,type->num_levels,&width,Atom);
383	    if (type->level_names!=NULL) {
384		for (n=0;n<wire.nLevelNames;n++) {
385		    if ((tmp=XkmGetCountedString(file,buf,100))<1)
386			return -1;
387		    nRead+= tmp;
388		    if (strlen(buf)==0)
389			 type->level_names[n]= None;
390		    else type->level_names[n]= XkbInternAtom(buf,0);
391		}
392	    }
393	}
394	type->mods.mask= wire.realMods;
395	type->mods.real_mods= wire.realMods;
396	type->mods.vmods= wire.virtualMods;
397	type->num_levels= wire.numLevels;
398	type->map_count= wire.nMapEntries;
399    }
400    if (changes) {
401	changes->map.changed|= XkbKeyTypesMask;
402	changes->map.first_type= 0;
403	changes->map.num_types= xkb->map->num_types;
404    }
405    return nRead;
406}
407
408/***====================================================================***/
409
410static int
411ReadXkmCompatMap(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
412{
413register int		i;
414unsigned		num_si,groups;
415char 			name[100];
416XkbSymInterpretPtr	interp;
417xkmSymInterpretDesc	wire;
418unsigned		tmp;
419int			nRead=0;
420XkbCompatMapPtr		compat;
421
422    if ((tmp= XkmGetCountedString(file,name,100))<1) {
423	_XkbLibError(_XkbErrBadLength,"ReadXkmCompatMap",0);
424	return -1;
425    }
426    nRead+= tmp;
427    if (name[0]!='\0') {
428	if (XkbAllocNames(xkb,XkbCompatNameMask,0,0)!=Success) {
429	    _XkbLibError(_XkbErrBadAlloc,"ReadXkmCompatMap",0);
430	    return -1;
431	}
432	xkb->names->compat= XkbInternAtom(name,False);
433    }
434    num_si= XkmGetCARD16(file,&nRead);
435    groups= XkmGetCARD8(file,&nRead);
436    nRead+= XkmSkipPadding(file,1);
437    if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_si)!=Success)
438	return -1;
439    compat= xkb->compat;
440    compat->num_si= num_si;
441    interp= compat->sym_interpret;
442    for (i=0;i<num_si;i++,interp++) {
443	tmp= fread(&wire,SIZEOF(xkmSymInterpretDesc),1,file);
444	nRead+= tmp*SIZEOF(xkmSymInterpretDesc);
445	interp->sym= wire.sym;
446	interp->mods= wire.mods;
447	interp->match= wire.match;
448	interp->virtual_mod= wire.virtualMod;
449	interp->flags= wire.flags;
450	interp->act.type= wire.actionType;
451	interp->act.data[0]= wire.actionData[0];
452	interp->act.data[1]= wire.actionData[1];
453	interp->act.data[2]= wire.actionData[2];
454	interp->act.data[3]= wire.actionData[3];
455	interp->act.data[4]= wire.actionData[4];
456	interp->act.data[5]= wire.actionData[5];
457	interp->act.data[6]= wire.actionData[6];
458    }
459    if ((num_si>0)&&(changes)) {
460	changes->compat.first_si= 0;
461	changes->compat.num_si= num_si;
462    }
463    if (groups) {
464	register unsigned bit;
465	for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
466	    xkmModsDesc	md;
467	    if (groups&bit) {
468		tmp= fread(&md,SIZEOF(xkmModsDesc),1,file);
469		nRead+= tmp*SIZEOF(xkmModsDesc);
470		xkb->compat->groups[i].real_mods= md.realMods;
471		xkb->compat->groups[i].vmods= md.virtualMods;
472		if (md.virtualMods != 0) {
473		    unsigned mask;
474		    if (XkbVirtualModsToReal(xkb,md.virtualMods,&mask))
475			xkb->compat->groups[i].mask= md.realMods|mask;
476		}
477		else xkb->compat->groups[i].mask= md.realMods;
478	    }
479	}
480	if (changes)
481	    changes->compat.changed_groups|= groups;
482    }
483    return nRead;
484}
485
486static int
487ReadXkmIndicators(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
488{
489register unsigned	nLEDs;
490xkmIndicatorMapDesc	wire;
491char			buf[100];
492unsigned		tmp;
493int			nRead=0;
494
495    if ((xkb->indicators==NULL)&&(XkbAllocIndicatorMaps(xkb)!=Success)) {
496	_XkbLibError(_XkbErrBadAlloc,"indicator rec",0);
497	return -1;
498    }
499    if (XkbAllocNames(xkb,XkbIndicatorNamesMask,0,0)!=Success) {
500	_XkbLibError(_XkbErrBadAlloc,"indicator names",0);
501	return -1;
502    }
503    nLEDs= XkmGetCARD8(file,&nRead);
504    nRead+= XkmSkipPadding(file,3);
505    xkb->indicators->phys_indicators= XkmGetCARD32(file,&nRead);
506    while (nLEDs-->0) {
507	Atom 			name;
508	XkbIndicatorMapPtr	map;
509
510	if ((tmp=XkmGetCountedString(file,buf,100))<1) {
511	    _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0);
512	    return -1;
513	}
514	nRead+= tmp;
515	if (buf[0]!='\0')
516	     name= XkbInternAtom(buf,False);
517	else name= None;
518	if ((tmp=fread(&wire,SIZEOF(xkmIndicatorMapDesc),1,file))<1) {
519	    _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0);
520	    return -1;
521	}
522	nRead+= tmp*SIZEOF(xkmIndicatorMapDesc);
523	if (xkb->names) {
524	    xkb->names->indicators[wire.indicator-1]= name;
525	    if (changes)
526		changes->names.changed_indicators|= (1<<(wire.indicator-1));
527	}
528	map= &xkb->indicators->maps[wire.indicator-1];
529	map->flags= wire.flags;
530	map->which_groups= wire.which_groups;
531	map->groups= wire.groups;
532	map->which_mods= wire.which_mods;
533	map->mods.mask= wire.real_mods;
534	map->mods.real_mods= wire.real_mods;
535	map->mods.vmods= wire.vmods;
536	map->ctrls= wire.ctrls;
537    }
538    return nRead;
539}
540
541static XkbKeyTypePtr
542FindTypeForKey(XkbDescPtr xkb,Atom name,unsigned width,KeySym *syms)
543{
544    if ((!xkb)||(!xkb->map))
545	return NULL;
546    if (name!=None) {
547	register unsigned i;
548	for (i=0;i<xkb->map->num_types;i++) {
549	    if (xkb->map->types[i].name==name) {
550		if (xkb->map->types[i].num_levels!=width)
551		    DebugF("Group width mismatch between key and type\n");
552		return &xkb->map->types[i];
553	    }
554	}
555    }
556    if ((width<2)||((syms!=NULL)&&(syms[1]==NoSymbol)))
557	return &xkb->map->types[XkbOneLevelIndex];
558    if (syms!=NULL) {
559	if (XkbKSIsLower(syms[0])&&XkbKSIsUpper(syms[1]))
560	    return &xkb->map->types[XkbAlphabeticIndex];
561	else if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1]))
562	    return &xkb->map->types[XkbKeypadIndex];
563    }
564    return &xkb->map->types[XkbTwoLevelIndex];
565}
566
567static int
568ReadXkmSymbols(FILE *file,XkbDescPtr xkb)
569{
570register int		i,g,s,totalVModMaps;
571xkmKeySymMapDesc 	wireMap;
572char 			buf[100];
573unsigned		minKC,maxKC,groupNames,tmp;
574int			nRead=0;
575
576    if ((tmp=XkmGetCountedString(file,buf,100))<1)
577	return -1;
578    nRead+= tmp;
579    minKC= XkmGetCARD8(file,&nRead);
580    maxKC= XkmGetCARD8(file,&nRead);
581    groupNames= XkmGetCARD8(file,&nRead);
582    totalVModMaps= XkmGetCARD8(file,&nRead);
583    if (XkbAllocNames(xkb,
584	      XkbSymbolsNameMask|XkbPhysSymbolsNameMask|XkbGroupNamesMask,
585	      0,0)!=Success) {
586	_XkbLibError(_XkbErrBadAlloc,"physical names",0);
587	return -1;
588    }
589    if ((buf[0]!='\0')&&(xkb->names)) {
590	Atom name;
591	name= XkbInternAtom(buf,0);
592	xkb->names->symbols= name;
593	xkb->names->phys_symbols= name;
594    }
595    for (i=0,g=1;i<XkbNumKbdGroups;i++,g<<=1) {
596	if (groupNames&g) {
597	    if ((tmp=XkmGetCountedString(file,buf,100))<1)
598		return -1;
599	    nRead+= tmp;
600	    if ((buf[0]!='\0')&&(xkb->names)) {
601		Atom name;
602		name= XkbInternAtom(buf,0);
603		xkb->names->groups[i]= name;
604	    }
605	    else xkb->names->groups[i]= None;
606	}
607    }
608    if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success) {
609	_XkbLibError(_XkbErrBadAlloc,"server map",0);
610	return -1;
611    }
612    if (XkbAllocClientMap(xkb,XkbAllClientInfoMask,0)!=Success) {
613	_XkbLibError(_XkbErrBadAlloc,"client map",0);
614	return -1;
615    }
616    if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success) {
617	_XkbLibError(_XkbErrBadAlloc,"controls",0);
618	return -1;
619    }
620    if ((xkb->map==NULL)||(xkb->server==NULL))
621	return -1;
622    if (xkb->min_key_code<8)	xkb->min_key_code= minKC;
623    if (xkb->max_key_code<8)	xkb->max_key_code= maxKC;
624    if ((minKC>=8)&&(minKC<xkb->min_key_code))
625	xkb->min_key_code= minKC;
626    if ((maxKC>=8)&&(maxKC>xkb->max_key_code)) {
627	_XkbLibError(_XkbErrBadValue,"keys in symbol map",maxKC);
628	return -1;
629    }
630    for (i=minKC;i<=(int)maxKC;i++)  {
631	Atom 		typeName[XkbNumKbdGroups];
632	XkbKeyTypePtr	type[XkbNumKbdGroups];
633	if ((tmp=fread(&wireMap,SIZEOF(xkmKeySymMapDesc),1,file))<1) {
634	    _XkbLibError(_XkbErrBadLength,"ReadXkmSymbols",0);
635	    return -1;
636	}
637	nRead+= tmp*SIZEOF(xkmKeySymMapDesc);
638	bzero((char *)typeName,XkbNumKbdGroups*sizeof(Atom));
639	bzero((char *)type,XkbNumKbdGroups*sizeof(XkbKeyTypePtr));
640	if (wireMap.flags&XkmKeyHasTypes) {
641	    register int g;
642	    for (g=0;g<XkbNumKbdGroups;g++) {
643		if ((wireMap.flags&(1<<g))&&
644			((tmp=XkmGetCountedString(file,buf,100))>0)) {
645		    typeName[g]= XkbInternAtom(buf,1);
646		    nRead+= tmp;
647		}
648		type[g]=FindTypeForKey(xkb,typeName[g],wireMap.width,NULL);
649		if (type[g]==NULL) {
650		    _XkbLibError(_XkbErrMissingTypes,"ReadXkmSymbols",0);
651		    return -1;
652		}
653		if (typeName[g]==type[g]->name)
654		    xkb->server->explicit[i]|= (1<<g);
655	    }
656	}
657	if (wireMap.flags&XkmRepeatingKey) {
658	    xkb->ctrls->per_key_repeat[i/8]|= (1<<(i%8));
659	    xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask;
660	}
661	else if (wireMap.flags&XkmNonRepeatingKey) {
662	    xkb->ctrls->per_key_repeat[i/8]&= ~(1<<(i%8));
663	    xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask;
664	}
665	xkb->map->modmap[i]= wireMap.modifier_map;
666	if (XkbNumGroups(wireMap.num_groups)>0) {
667	    KeySym	*sym;
668	    int		 nSyms;
669
670	    if (XkbNumGroups(wireMap.num_groups)>xkb->ctrls->num_groups)
671		xkb->ctrls->num_groups= wireMap.num_groups;
672	    nSyms= XkbNumGroups(wireMap.num_groups)*wireMap.width;
673	    sym= XkbResizeKeySyms(xkb,i,nSyms);
674	    if (!sym)
675		return -1;
676	    for (s=0;s<nSyms;s++) {
677		*sym++= XkmGetCARD32(file,&nRead);
678	    }
679	    if (wireMap.flags&XkmKeyHasActions) {
680		XkbAction *	act;
681		act= XkbResizeKeyActions(xkb,i,nSyms);
682		for (s=0;s<nSyms;s++,act++) {
683		    tmp=fread(act,SIZEOF(xkmActionDesc),1,file);
684		    nRead+= tmp*SIZEOF(xkmActionDesc);
685		}
686		xkb->server->explicit[i]|= XkbExplicitInterpretMask;
687	    }
688	}
689	for (g=0;g<XkbNumGroups(wireMap.num_groups);g++) {
690	    if (((xkb->server->explicit[i]&(1<<g))==0)||(type[g]==NULL)) {
691		KeySym *tmpSyms;
692		tmpSyms= XkbKeySymsPtr(xkb,i)+(wireMap.width*g);
693		type[g]= FindTypeForKey(xkb,None,wireMap.width,tmpSyms);
694	    }
695	    xkb->map->key_sym_map[i].kt_index[g]= type[g]-(&xkb->map->types[0]);
696	}
697	xkb->map->key_sym_map[i].group_info= wireMap.num_groups;
698	xkb->map->key_sym_map[i].width= wireMap.width;
699	if (wireMap.flags&XkmKeyHasBehavior) {
700	    xkmBehaviorDesc	b;
701	    tmp= fread(&b,SIZEOF(xkmBehaviorDesc),1,file);
702	    nRead+= tmp*SIZEOF(xkmBehaviorDesc);
703	    xkb->server->behaviors[i].type= b.type;
704	    xkb->server->behaviors[i].data= b.data;
705	    xkb->server->explicit[i]|= XkbExplicitBehaviorMask;
706	}
707    }
708    if (totalVModMaps>0) {
709	xkmVModMapDesc	v;
710	for (i=0;i<totalVModMaps;i++) {
711	    tmp= fread(&v,SIZEOF(xkmVModMapDesc),1,file);
712	    nRead+= tmp*SIZEOF(xkmVModMapDesc);
713	    if (tmp>0)
714		xkb->server->vmodmap[v.key]= v.vmods;
715	}
716    }
717    return nRead;
718}
719
720static int
721ReadXkmGeomDoodad(
722    FILE *		file,
723    XkbGeometryPtr	geom,
724    XkbSectionPtr	section)
725{
726XkbDoodadPtr	doodad;
727xkmDoodadDesc	doodadWire;
728char		buf[100];
729unsigned	tmp;
730int		nRead=0;
731
732    nRead+= XkmGetCountedString(file,buf,100);
733    tmp= fread(&doodadWire,SIZEOF(xkmDoodadDesc),1,file);
734    nRead+= SIZEOF(xkmDoodadDesc)*tmp;
735    doodad= XkbAddGeomDoodad(geom,section,XkbInternAtom(buf,False));
736    if (!doodad)
737	return nRead;
738    doodad->any.type= doodadWire.any.type;
739    doodad->any.priority= doodadWire.any.priority;
740    doodad->any.top= doodadWire.any.top;
741    doodad->any.left= doodadWire.any.left;
742    switch (doodadWire.any.type) {
743	case XkbOutlineDoodad:
744	case XkbSolidDoodad:
745	    doodad->shape.angle= doodadWire.shape.angle;
746	    doodad->shape.color_ndx= doodadWire.shape.color_ndx;
747	    doodad->shape.shape_ndx= doodadWire.shape.shape_ndx;
748	    break;
749	case XkbTextDoodad:
750	    doodad->text.angle= doodadWire.text.angle;
751	    doodad->text.width= doodadWire.text.width;
752	    doodad->text.height= doodadWire.text.height;
753	    doodad->text.color_ndx= doodadWire.text.color_ndx;
754	    nRead+= XkmGetCountedString(file,buf,100);
755	    doodad->text.text= _XkbDupString(buf);
756	    nRead+= XkmGetCountedString(file,buf,100);
757	    doodad->text.font= _XkbDupString(buf);
758	    break;
759	case XkbIndicatorDoodad:
760	    doodad->indicator.shape_ndx= doodadWire.indicator.shape_ndx;
761	    doodad->indicator.on_color_ndx= doodadWire.indicator.on_color_ndx;
762	    doodad->indicator.off_color_ndx= doodadWire.indicator.off_color_ndx;
763	    break;
764	case XkbLogoDoodad:
765	    doodad->logo.angle= doodadWire.logo.angle;
766	    doodad->logo.color_ndx= doodadWire.logo.color_ndx;
767	    doodad->logo.shape_ndx= doodadWire.logo.shape_ndx;
768	    nRead+= XkmGetCountedString(file,buf,100);
769	    doodad->logo.logo_name= _XkbDupString(buf);
770	    break;
771	default:
772	    /* report error? */
773	    return nRead;
774    }
775    return nRead;
776}
777
778static int
779ReadXkmGeomOverlay(	FILE *		file,
780			XkbGeometryPtr	geom,
781			XkbSectionPtr	section)
782{
783char 			buf[100];
784unsigned		tmp;
785int			nRead=0;
786XkbOverlayPtr		ol;
787XkbOverlayRowPtr	row;
788xkmOverlayDesc 		olWire;
789xkmOverlayRowDesc	rowWire;
790register int		r;
791
792    nRead+= XkmGetCountedString(file,buf,100);
793    tmp= fread(&olWire,SIZEOF(xkmOverlayDesc),1,file);
794    nRead+= tmp*SIZEOF(xkmOverlayDesc);
795    ol= XkbAddGeomOverlay(section,XkbInternAtom(buf,False),
796    							olWire.num_rows);
797    if (!ol)
798	return nRead;
799    for (r=0;r<olWire.num_rows;r++)  {
800    	int			k;
801	xkmOverlayKeyDesc	keyWire;
802	tmp= fread(&rowWire,SIZEOF(xkmOverlayRowDesc),1,file);
803	nRead+= tmp*SIZEOF(xkmOverlayRowDesc);
804	row= XkbAddGeomOverlayRow(ol,rowWire.row_under,rowWire.num_keys);
805	if (!row) {
806	    _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomOverlay",0);
807	   return nRead;
808	}
809	for (k=0;k<rowWire.num_keys;k++) {
810	    tmp= fread(&keyWire,SIZEOF(xkmOverlayKeyDesc),1,file);
811	    nRead+= tmp*SIZEOF(xkmOverlayKeyDesc);
812	    memcpy(row->keys[k].over.name,keyWire.over,XkbKeyNameLength);
813	    memcpy(row->keys[k].under.name,keyWire.under,XkbKeyNameLength);
814	}
815	row->num_keys= rowWire.num_keys;
816    }
817    return nRead;
818}
819
820static int
821ReadXkmGeomSection(	FILE *		file,
822			XkbGeometryPtr	geom)
823{
824register int	i;
825XkbSectionPtr	section;
826xkmSectionDesc	sectionWire;
827unsigned	tmp;
828int		nRead= 0;
829char		buf[100];
830Atom		nameAtom;
831
832    nRead+= XkmGetCountedString(file,buf,100);
833    nameAtom= XkbInternAtom(buf,False);
834    tmp= fread(&sectionWire,SIZEOF(xkmSectionDesc),1,file);
835    nRead+= SIZEOF(xkmSectionDesc)*tmp;
836    section= XkbAddGeomSection(geom,nameAtom,sectionWire.num_rows,
837			 			sectionWire.num_doodads,
838			 			sectionWire.num_overlays);
839    if (!section) {
840	_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0);
841	return nRead;
842    }
843    section->top= sectionWire.top;
844    section->left= sectionWire.left;
845    section->width= sectionWire.width;
846    section->height= sectionWire.height;
847    section->angle= sectionWire.angle;
848    section->priority= sectionWire.priority;
849    if (sectionWire.num_rows>0) {
850	register int	k;
851	XkbRowPtr	row;
852	xkmRowDesc	rowWire;
853	XkbKeyPtr	key;
854	xkmKeyDesc	keyWire;
855
856	for (i=0;i<sectionWire.num_rows;i++) {
857	    tmp= fread(&rowWire,SIZEOF(xkmRowDesc),1,file);
858	    nRead+= SIZEOF(xkmRowDesc)*tmp;
859	    row= XkbAddGeomRow(section,rowWire.num_keys);
860	    if (!row) {
861		_XkbLibError(_XkbErrBadAlloc,"ReadXkmKeycodes",0);
862		return nRead;
863	    }
864	    row->top= rowWire.top;
865	    row->left= rowWire.left;
866	    row->vertical= rowWire.vertical;
867	    for (k=0;k<rowWire.num_keys;k++) {
868		tmp= fread(&keyWire,SIZEOF(xkmKeyDesc),1,file);
869		nRead+= SIZEOF(xkmKeyDesc)*tmp;
870		key= XkbAddGeomKey(row);
871		if (!key) {
872		    _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0);
873		    return nRead;
874		}
875		memcpy(key->name.name,keyWire.name,XkbKeyNameLength);
876		key->gap= keyWire.gap;
877		key->shape_ndx= keyWire.shape_ndx;
878		key->color_ndx= keyWire.color_ndx;
879	    }
880	}
881    }
882    if (sectionWire.num_doodads>0) {
883	for (i=0;i<sectionWire.num_doodads;i++) {
884	    tmp= ReadXkmGeomDoodad(file,geom,section);
885	    nRead+= tmp;
886	    if (tmp<1)
887		return nRead;
888	}
889    }
890    if (sectionWire.num_overlays>0) {
891	for (i=0;i<sectionWire.num_overlays;i++) {
892	    tmp= ReadXkmGeomOverlay(file,geom,section);
893	    nRead+= tmp;
894	    if (tmp<1)
895		return nRead;
896	}
897    }
898    return nRead;
899}
900
901static int
902ReadXkmGeometry(FILE *file,XkbDescPtr xkb)
903{
904register int		i;
905char 			buf[100];
906unsigned		tmp;
907int			nRead= 0;
908xkmGeometryDesc		wireGeom;
909XkbGeometryPtr		geom;
910XkbGeometrySizesRec	sizes;
911
912    nRead+= XkmGetCountedString(file,buf,100);
913    tmp= fread(&wireGeom,SIZEOF(xkmGeometryDesc),1,file);
914    nRead+= tmp*SIZEOF(xkmGeometryDesc);
915    sizes.which= XkbGeomAllMask;
916    sizes.num_properties= wireGeom.num_properties;
917    sizes.num_colors= wireGeom.num_colors;
918    sizes.num_shapes= wireGeom.num_shapes;
919    sizes.num_sections= wireGeom.num_sections;
920    sizes.num_doodads= wireGeom.num_doodads;
921    sizes.num_key_aliases= wireGeom.num_key_aliases;
922    if (XkbAllocGeometry(xkb,&sizes)!=Success) {
923	_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
924	return nRead;
925    }
926    geom= xkb->geom;
927    geom->name= XkbInternAtom(buf,False);
928    geom->width_mm= wireGeom.width_mm;
929    geom->height_mm= wireGeom.height_mm;
930    nRead+= XkmGetCountedString(file,buf,100);
931    geom->label_font= _XkbDupString(buf);
932    if (wireGeom.num_properties>0) {
933	char val[1024];
934	for (i=0;i<wireGeom.num_properties;i++) {
935	    nRead+= XkmGetCountedString(file,buf,100);
936	    nRead+= XkmGetCountedString(file,val,1024);
937	    if (XkbAddGeomProperty(geom,buf,val)==NULL) {
938		_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
939		return nRead;
940	    }
941	}
942    }
943    if (wireGeom.num_colors>0) {
944	for (i=0;i<wireGeom.num_colors;i++) {
945	    nRead+= XkmGetCountedString(file,buf,100);
946	    if (XkbAddGeomColor(geom,buf,i)==NULL) {
947		_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
948		return nRead;
949	    }
950	}
951    }
952    geom->base_color= &geom->colors[wireGeom.base_color_ndx];
953    geom->label_color= &geom->colors[wireGeom.label_color_ndx];
954    if (wireGeom.num_shapes>0) {
955	XkbShapePtr	shape;
956	xkmShapeDesc	shapeWire;
957	Atom		nameAtom;
958	for (i=0;i<wireGeom.num_shapes;i++) {
959	    register int 	n;
960	    XkbOutlinePtr	ol;
961	    xkmOutlineDesc	olWire;
962	    nRead+= XkmGetCountedString(file,buf,100);
963	    nameAtom= XkbInternAtom(buf,False);
964	    tmp= fread(&shapeWire,SIZEOF(xkmShapeDesc),1,file);
965	    nRead+= tmp*SIZEOF(xkmShapeDesc);
966	    shape= XkbAddGeomShape(geom,nameAtom,shapeWire.num_outlines);
967	    if (!shape) {
968		_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
969		return nRead;
970	    }
971	    for (n=0;n<shapeWire.num_outlines;n++) {
972		register int	p;
973		xkmPointDesc	ptWire;
974		tmp= fread(&olWire,SIZEOF(xkmOutlineDesc),1,file);
975		nRead+= tmp*SIZEOF(xkmOutlineDesc);
976		ol= XkbAddGeomOutline(shape,olWire.num_points);
977		if (!ol) {
978		    _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
979		    return nRead;
980		}
981		ol->num_points= olWire.num_points;
982		ol->corner_radius= olWire.corner_radius;
983		for (p=0;p<olWire.num_points;p++) {
984		    tmp= fread(&ptWire,SIZEOF(xkmPointDesc),1,file);
985		    nRead+= tmp*SIZEOF(xkmPointDesc);
986		    ol->points[p].x= ptWire.x;
987		    ol->points[p].y= ptWire.y;
988		    if (ptWire.x<shape->bounds.x1) shape->bounds.x1= ptWire.x;
989		    if (ptWire.x>shape->bounds.x2) shape->bounds.x2= ptWire.x;
990		    if (ptWire.y<shape->bounds.y1) shape->bounds.y1= ptWire.y;
991		    if (ptWire.y>shape->bounds.y2) shape->bounds.y2= ptWire.y;
992		}
993	    }
994	    if (shapeWire.primary_ndx!=XkbNoShape)
995		shape->primary= &shape->outlines[shapeWire.primary_ndx];
996	    if (shapeWire.approx_ndx!=XkbNoShape)
997		shape->approx= &shape->outlines[shapeWire.approx_ndx];
998	}
999    }
1000    if (wireGeom.num_sections>0) {
1001	for (i=0;i<wireGeom.num_sections;i++) {
1002	    tmp= ReadXkmGeomSection(file,geom);
1003	    nRead+= tmp;
1004	    if (tmp==0)
1005		return nRead;
1006	}
1007    }
1008    if (wireGeom.num_doodads>0) {
1009	for (i=0;i<wireGeom.num_doodads;i++) {
1010	    tmp= ReadXkmGeomDoodad(file,geom,NULL);
1011	    nRead+= tmp;
1012	    if (tmp==0)
1013		return nRead;
1014	}
1015    }
1016    if ((wireGeom.num_key_aliases>0)&&(geom->key_aliases)) {
1017	int sz= XkbKeyNameLength*2;
1018	int num= wireGeom.num_key_aliases;
1019	if (fread(geom->key_aliases,sz,num,file)!=num) {
1020	    _XkbLibError(_XkbErrBadLength,"ReadXkmGeometry",0);
1021	    return -1;
1022	}
1023	nRead+= (num*sz);
1024	geom->num_key_aliases= num;
1025    }
1026    return nRead;
1027}
1028
1029Bool
1030XkmProbe(FILE *file)
1031{
1032unsigned hdr,tmp;
1033int	 nRead=0;
1034
1035    hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion);
1036    tmp= XkmGetCARD32(file,&nRead);
1037    if (tmp!=hdr) {
1038	if ((tmp&(~0xff))==(hdr&(~0xff))) {
1039	    _XkbLibError(_XkbErrBadFileVersion,"XkmProbe",tmp&0xff);
1040	}
1041	return 0;
1042    }
1043    return 1;
1044}
1045
1046static Bool
1047XkmReadTOC(FILE *file,xkmFileInfo* file_info,int max_toc,xkmSectionInfo *toc)
1048{
1049unsigned hdr,tmp;
1050int	nRead=0;
1051unsigned i,size_toc;
1052
1053    hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion);
1054    tmp= XkmGetCARD32(file,&nRead);
1055    if (tmp!=hdr) {
1056	if ((tmp&(~0xff))==(hdr&(~0xff))) {
1057	    _XkbLibError(_XkbErrBadFileVersion,"XkmReadTOC",tmp&0xff);
1058	}
1059	else {
1060	    _XkbLibError(_XkbErrBadFileType,"XkmReadTOC",tmp);
1061	}
1062	return 0;
1063    }
1064    fread(file_info,SIZEOF(xkmFileInfo),1,file);
1065    size_toc= file_info->num_toc;
1066    if (size_toc>max_toc) {
1067	DebugF("Warning! Too many TOC entries; last %d ignored\n",
1068							size_toc-max_toc);
1069	size_toc= max_toc;
1070    }
1071    for (i=0;i<size_toc;i++) {
1072	fread(&toc[i],SIZEOF(xkmSectionInfo),1,file);
1073    }
1074    return 1;
1075}
1076
1077/***====================================================================***/
1078
1079#define	MAX_TOC	16
1080unsigned
1081XkmReadFile(FILE *file,unsigned need,unsigned want,XkbDescPtr *xkb)
1082{
1083register unsigned	i;
1084xkmSectionInfo		toc[MAX_TOC],tmpTOC;
1085xkmFileInfo		fileInfo;
1086unsigned		tmp,nRead=0;
1087unsigned		which= need|want;
1088
1089    if (!XkmReadTOC(file,&fileInfo,MAX_TOC,toc))
1090	return which;
1091    if ((fileInfo.present&need)!=need) {
1092       _XkbLibError(_XkbErrIllegalContents,"XkmReadFile",
1093       						need&(~fileInfo.present));
1094       return which;
1095    }
1096    if (*xkb==NULL)
1097	*xkb= XkbAllocKeyboard();
1098    for (i=0;i<fileInfo.num_toc;i++) {
1099	fseek(file,toc[i].offset,SEEK_SET);
1100	tmp= fread(&tmpTOC,SIZEOF(xkmSectionInfo),1,file);
1101	nRead= tmp*SIZEOF(xkmSectionInfo);
1102	if ((tmpTOC.type!=toc[i].type)||(tmpTOC.format!=toc[i].format)||
1103	    (tmpTOC.size!=toc[i].size)||(tmpTOC.offset!=toc[i].offset)) {
1104	    return which;
1105	}
1106	if ((which&(1<<tmpTOC.type))==0) {
1107	    continue;
1108	}
1109	switch (tmpTOC.type) {
1110	    case XkmVirtualModsIndex:
1111		tmp= ReadXkmVirtualMods(file,*xkb,NULL);
1112		break;
1113	    case XkmTypesIndex:
1114		tmp= ReadXkmKeyTypes(file,*xkb,NULL);
1115		break;
1116	    case XkmCompatMapIndex:
1117		tmp= ReadXkmCompatMap(file,*xkb,NULL);
1118		break;
1119	    case XkmKeyNamesIndex:
1120		tmp= ReadXkmKeycodes(file,*xkb,NULL);
1121		break;
1122	    case XkmIndicatorsIndex:
1123		tmp= ReadXkmIndicators(file,*xkb,NULL);
1124		break;
1125	    case XkmSymbolsIndex:
1126		tmp= ReadXkmSymbols(file,*xkb);
1127		break;
1128	    case XkmGeometryIndex:
1129		tmp= ReadXkmGeometry(file,*xkb);
1130		break;
1131	    default:
1132		_XkbLibError(_XkbErrBadImplementation,
1133				XkbConfigText(tmpTOC.type,XkbMessage),0);
1134		tmp= 0;
1135		break;
1136	}
1137	if (tmp>0) {
1138	    nRead+= tmp;
1139	    which&= ~(1<<toc[i].type);
1140	    (*xkb)->defined|= (1<<toc[i].type);
1141	}
1142	if (nRead!=tmpTOC.size) {
1143	    _XkbLibError(_XkbErrBadLength,XkbConfigText(tmpTOC.type,XkbMessage),
1144	    						nRead-tmpTOC.size);
1145	}
1146    }
1147    return which;
1148}
1149