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#include <X11/Xproto.h>
38#include <X11/keysym.h>
39#include <X11/extensions/XKMformat.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(const char *str)
56{
57char *new;
58
59   if (str==NULL)
60	return NULL;
61   new= calloc(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= calloc(newCount,elemSize);
78    }
79    else if (oldCount<newCount) {
80	oldPtr= realloc(oldPtr,newCount*elemSize);
81	if (oldPtr!=NULL) {
82	    char *tmp= (char *)oldPtr;
83	    memset(&tmp[oldCount*elemSize], 0, (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;
421XkbAction               *act;
422
423    if ((tmp= XkmGetCountedString(file,name,100))<1) {
424	_XkbLibError(_XkbErrBadLength,"ReadXkmCompatMap",0);
425	return -1;
426    }
427    nRead+= tmp;
428    if (name[0]!='\0') {
429	if (XkbAllocNames(xkb,XkbCompatNameMask,0,0)!=Success) {
430	    _XkbLibError(_XkbErrBadAlloc,"ReadXkmCompatMap",0);
431	    return -1;
432	}
433	xkb->names->compat= XkbInternAtom(name,FALSE);
434    }
435    num_si= XkmGetCARD16(file,&nRead);
436    groups= XkmGetCARD8(file,&nRead);
437    nRead+= XkmSkipPadding(file,1);
438    if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_si)!=Success)
439	return -1;
440    compat= xkb->compat;
441    compat->num_si= num_si;
442    interp= compat->sym_interpret;
443    for (i=0;i<num_si;i++,interp++) {
444	tmp= fread(&wire,SIZEOF(xkmSymInterpretDesc),1,file);
445	nRead+= tmp*SIZEOF(xkmSymInterpretDesc);
446	interp->sym= wire.sym;
447	interp->mods= wire.mods;
448	interp->match= wire.match;
449	interp->virtual_mod= wire.virtualMod;
450	interp->flags= wire.flags;
451	interp->act.type= wire.actionType;
452        act = (XkbAction *) &interp->act;
453
454        switch (interp->act.type) {
455        case XkbSA_SetMods:
456        case XkbSA_LatchMods:
457        case XkbSA_LockMods:
458            act->mods.flags = wire.actionData[0];
459            act->mods.mask = wire.actionData[1];
460            act->mods.real_mods = wire.actionData[2];
461            act->mods.vmods1 = wire.actionData[3];
462            act->mods.vmods2 = wire.actionData[4];
463            break;
464        case XkbSA_SetGroup:
465        case XkbSA_LatchGroup:
466        case XkbSA_LockGroup:
467            act->group.flags = wire.actionData[0];
468            act->group.group_XXX = wire.actionData[1];
469            break;
470        case XkbSA_MovePtr:
471            act->ptr.flags = wire.actionData[0];
472            act->ptr.high_XXX = wire.actionData[1];
473            act->ptr.low_XXX = wire.actionData[2];
474            act->ptr.high_YYY = wire.actionData[3];
475            act->ptr.low_YYY = wire.actionData[4];
476            break;
477        case XkbSA_PtrBtn:
478        case XkbSA_LockPtrBtn:
479            act->btn.flags = wire.actionData[0];
480            act->btn.count = wire.actionData[1];
481            act->btn.button = wire.actionData[2];
482            break;
483        case XkbSA_DeviceBtn:
484        case XkbSA_LockDeviceBtn:
485            act->devbtn.flags = wire.actionData[0];
486            act->devbtn.count = wire.actionData[1];
487            act->devbtn.button = wire.actionData[2];
488            act->devbtn.device = wire.actionData[3];
489            break;
490        case XkbSA_SetPtrDflt:
491            act->dflt.flags = wire.actionData[0];
492            act->dflt.affect = wire.actionData[1];
493            act->dflt.valueXXX = wire.actionData[2];
494            break;
495        case XkbSA_ISOLock:
496            act->iso.flags = wire.actionData[0];
497            act->iso.mask = wire.actionData[1];
498            act->iso.real_mods = wire.actionData[2];
499            act->iso.group_XXX = wire.actionData[3];
500            act->iso.affect = wire.actionData[4];
501            act->iso.vmods1 = wire.actionData[5];
502            act->iso.vmods2 = wire.actionData[6];
503            break;
504        case XkbSA_SwitchScreen:
505            act->screen.flags = wire.actionData[0];
506            act->screen.screenXXX = wire.actionData[1];
507            break;
508        case XkbSA_SetControls:
509        case XkbSA_LockControls:
510            act->ctrls.flags = wire.actionData[0];
511            act->ctrls.ctrls3 = wire.actionData[1];
512            act->ctrls.ctrls2 = wire.actionData[2];
513            act->ctrls.ctrls1 = wire.actionData[3];
514            act->ctrls.ctrls0 = wire.actionData[4];
515            break;
516        case XkbSA_RedirectKey:
517            act->redirect.new_key = wire.actionData[0];
518            act->redirect.mods_mask = wire.actionData[1];
519            act->redirect.mods = wire.actionData[2];
520            act->redirect.vmods_mask0 = wire.actionData[3];
521            act->redirect.vmods_mask1 = wire.actionData[4];
522            act->redirect.vmods0 = wire.actionData[4];
523            act->redirect.vmods1 = wire.actionData[5];
524            break;
525        case XkbSA_DeviceValuator:
526            act->devval.device = wire.actionData[0];
527            act->devval.v1_what = wire.actionData[1];
528            act->devval.v1_ndx = wire.actionData[2];
529            act->devval.v1_value = wire.actionData[3];
530            act->devval.v2_what = wire.actionData[4];
531            act->devval.v2_ndx = wire.actionData[5];
532            act->devval.v2_what = wire.actionData[6];
533            break;
534
535        case XkbSA_XFree86Private:
536            /* copy the kind of action */
537            memcpy(act->any.data, wire.actionData, XkbAnyActionDataSize);
538            break ;
539
540        case XkbSA_Terminate:
541            /* no args, kinda (note: untrue for xfree86). */
542            break;
543        case XkbSA_ActionMessage:
544            /* unsupported. */
545            break;
546        }
547    }
548    if ((num_si>0)&&(changes)) {
549	changes->compat.first_si= 0;
550	changes->compat.num_si= num_si;
551    }
552    if (groups) {
553	register unsigned bit;
554	for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
555	    xkmModsDesc	md;
556	    if (groups&bit) {
557		tmp= fread(&md,SIZEOF(xkmModsDesc),1,file);
558		nRead+= tmp*SIZEOF(xkmModsDesc);
559		xkb->compat->groups[i].real_mods= md.realMods;
560		xkb->compat->groups[i].vmods= md.virtualMods;
561		if (md.virtualMods != 0) {
562		    unsigned mask;
563		    if (XkbVirtualModsToReal(xkb,md.virtualMods,&mask))
564			xkb->compat->groups[i].mask= md.realMods|mask;
565		}
566		else xkb->compat->groups[i].mask= md.realMods;
567	    }
568	}
569	if (changes)
570	    changes->compat.changed_groups|= groups;
571    }
572    return nRead;
573}
574
575static int
576ReadXkmIndicators(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
577{
578register unsigned	nLEDs;
579xkmIndicatorMapDesc	wire;
580char			buf[100];
581unsigned		tmp;
582int			nRead=0;
583
584    if ((xkb->indicators==NULL)&&(XkbAllocIndicatorMaps(xkb)!=Success)) {
585	_XkbLibError(_XkbErrBadAlloc,"indicator rec",0);
586	return -1;
587    }
588    if (XkbAllocNames(xkb,XkbIndicatorNamesMask,0,0)!=Success) {
589	_XkbLibError(_XkbErrBadAlloc,"indicator names",0);
590	return -1;
591    }
592    nLEDs= XkmGetCARD8(file,&nRead);
593    nRead+= XkmSkipPadding(file,3);
594    xkb->indicators->phys_indicators= XkmGetCARD32(file,&nRead);
595    while (nLEDs-->0) {
596	Atom 			name;
597	XkbIndicatorMapPtr	map;
598
599	if ((tmp=XkmGetCountedString(file,buf,100))<1) {
600	    _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0);
601	    return -1;
602	}
603	nRead+= tmp;
604	if (buf[0]!='\0')
605	     name= XkbInternAtom(buf,FALSE);
606	else name= None;
607	if ((tmp=fread(&wire,SIZEOF(xkmIndicatorMapDesc),1,file))<1) {
608	    _XkbLibError(_XkbErrBadLength,"ReadXkmIndicators",0);
609	    return -1;
610	}
611	nRead+= tmp*SIZEOF(xkmIndicatorMapDesc);
612	if (xkb->names) {
613	    xkb->names->indicators[wire.indicator-1]= name;
614	    if (changes)
615		changes->names.changed_indicators|= (1<<(wire.indicator-1));
616	}
617	map= &xkb->indicators->maps[wire.indicator-1];
618	map->flags= wire.flags;
619	map->which_groups= wire.which_groups;
620	map->groups= wire.groups;
621	map->which_mods= wire.which_mods;
622	map->mods.mask= wire.real_mods;
623	map->mods.real_mods= wire.real_mods;
624	map->mods.vmods= wire.vmods;
625	map->ctrls= wire.ctrls;
626    }
627    return nRead;
628}
629
630static XkbKeyTypePtr
631FindTypeForKey(XkbDescPtr xkb,Atom name,unsigned width,KeySym *syms)
632{
633    if ((!xkb)||(!xkb->map))
634	return NULL;
635    if (name!=None) {
636	register unsigned i;
637	for (i=0;i<xkb->map->num_types;i++) {
638	    if (xkb->map->types[i].name==name) {
639		if (xkb->map->types[i].num_levels!=width)
640		    DebugF("Group width mismatch between key and type\n");
641		return &xkb->map->types[i];
642	    }
643	}
644    }
645    if ((width<2)||((syms!=NULL)&&(syms[1]==NoSymbol)))
646	return &xkb->map->types[XkbOneLevelIndex];
647    if (syms!=NULL) {
648	if (XkbKSIsLower(syms[0])&&XkbKSIsUpper(syms[1]))
649	    return &xkb->map->types[XkbAlphabeticIndex];
650	else if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1]))
651	    return &xkb->map->types[XkbKeypadIndex];
652    }
653    return &xkb->map->types[XkbTwoLevelIndex];
654}
655
656static int
657ReadXkmSymbols(FILE *file,XkbDescPtr xkb)
658{
659register int		i,g,s,totalVModMaps;
660xkmKeySymMapDesc 	wireMap;
661char 			buf[100];
662unsigned		minKC,maxKC,groupNames,tmp;
663int			nRead=0;
664
665    if ((tmp=XkmGetCountedString(file,buf,100))<1)
666	return -1;
667    nRead+= tmp;
668    minKC= XkmGetCARD8(file,&nRead);
669    maxKC= XkmGetCARD8(file,&nRead);
670    groupNames= XkmGetCARD8(file,&nRead);
671    totalVModMaps= XkmGetCARD8(file,&nRead);
672    if (XkbAllocNames(xkb,
673	      XkbSymbolsNameMask|XkbPhysSymbolsNameMask|XkbGroupNamesMask,
674	      0,0)!=Success) {
675	_XkbLibError(_XkbErrBadAlloc,"physical names",0);
676	return -1;
677    }
678    if ((buf[0]!='\0')&&(xkb->names)) {
679	Atom name;
680	name= XkbInternAtom(buf,0);
681	xkb->names->symbols= name;
682	xkb->names->phys_symbols= name;
683    }
684    for (i=0,g=1;i<XkbNumKbdGroups;i++,g<<=1) {
685	if (groupNames&g) {
686	    if ((tmp=XkmGetCountedString(file,buf,100))<1)
687		return -1;
688	    nRead+= tmp;
689
690	    if (!xkb->names)
691		    continue;
692
693	    if (buf[0]!='\0') {
694		Atom name;
695		name= XkbInternAtom(buf,0);
696		xkb->names->groups[i]= name;
697	    }
698	    else xkb->names->groups[i]= None;
699	}
700    }
701    if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success) {
702	_XkbLibError(_XkbErrBadAlloc,"server map",0);
703	return -1;
704    }
705    if (XkbAllocClientMap(xkb,XkbAllClientInfoMask,0)!=Success) {
706	_XkbLibError(_XkbErrBadAlloc,"client map",0);
707	return -1;
708    }
709    if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success) {
710	_XkbLibError(_XkbErrBadAlloc,"controls",0);
711	return -1;
712    }
713    if ((xkb->map==NULL)||(xkb->server==NULL))
714	return -1;
715    if (xkb->min_key_code<8)	xkb->min_key_code= minKC;
716    if (xkb->max_key_code<8)	xkb->max_key_code= maxKC;
717    if ((minKC>=8)&&(minKC<xkb->min_key_code))
718	xkb->min_key_code= minKC;
719    if ((maxKC>=8)&&(maxKC>xkb->max_key_code)) {
720	_XkbLibError(_XkbErrBadValue,"keys in symbol map",maxKC);
721	return -1;
722    }
723    for (i=minKC;i<=(int)maxKC;i++)  {
724	Atom 		typeName[XkbNumKbdGroups];
725	XkbKeyTypePtr	type[XkbNumKbdGroups];
726	if ((tmp=fread(&wireMap,SIZEOF(xkmKeySymMapDesc),1,file))<1) {
727	    _XkbLibError(_XkbErrBadLength,"ReadXkmSymbols",0);
728	    return -1;
729	}
730	nRead+= tmp*SIZEOF(xkmKeySymMapDesc);
731	memset((char *)typeName, 0, XkbNumKbdGroups*sizeof(Atom));
732	memset((char *)type, 0, XkbNumKbdGroups*sizeof(XkbKeyTypePtr));
733	if (wireMap.flags&XkmKeyHasTypes) {
734	    register int g;
735	    for (g=0;g<XkbNumKbdGroups;g++) {
736		if ((wireMap.flags&(1<<g))&&
737			((tmp=XkmGetCountedString(file,buf,100))>0)) {
738		    typeName[g]= XkbInternAtom(buf,1);
739		    nRead+= tmp;
740		}
741		type[g]=FindTypeForKey(xkb,typeName[g],wireMap.width,NULL);
742		if (type[g]==NULL) {
743		    _XkbLibError(_XkbErrMissingTypes,"ReadXkmSymbols",0);
744		    return -1;
745		}
746		if (typeName[g]==type[g]->name)
747		    xkb->server->explicit[i]|= (1<<g);
748	    }
749	}
750	if (wireMap.flags&XkmRepeatingKey) {
751	    xkb->ctrls->per_key_repeat[i/8]|= (1<<(i%8));
752	    xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask;
753	}
754	else if (wireMap.flags&XkmNonRepeatingKey) {
755	    xkb->ctrls->per_key_repeat[i/8]&= ~(1<<(i%8));
756	    xkb->server->explicit[i]|= XkbExplicitAutoRepeatMask;
757	}
758	xkb->map->modmap[i]= wireMap.modifier_map;
759	if (XkbNumGroups(wireMap.num_groups)>0) {
760	    KeySym	*sym;
761	    int		 nSyms;
762
763	    if (XkbNumGroups(wireMap.num_groups)>xkb->ctrls->num_groups)
764		xkb->ctrls->num_groups= wireMap.num_groups;
765	    nSyms= XkbNumGroups(wireMap.num_groups)*wireMap.width;
766	    sym= XkbResizeKeySyms(xkb,i,nSyms);
767	    if (!sym)
768		return -1;
769	    for (s=0;s<nSyms;s++) {
770		*sym++= XkmGetCARD32(file,&nRead);
771	    }
772	    if (wireMap.flags&XkmKeyHasActions) {
773		XkbAction *	act;
774		act= XkbResizeKeyActions(xkb,i,nSyms);
775		for (s=0;s<nSyms;s++,act++) {
776		    tmp=fread(act,SIZEOF(xkmActionDesc),1,file);
777		    nRead+= tmp*SIZEOF(xkmActionDesc);
778		}
779		xkb->server->explicit[i]|= XkbExplicitInterpretMask;
780	    }
781	}
782	for (g=0;g<XkbNumGroups(wireMap.num_groups);g++) {
783	    if (((xkb->server->explicit[i]&(1<<g))==0)||(type[g]==NULL)) {
784		KeySym *tmpSyms;
785		tmpSyms= XkbKeySymsPtr(xkb,i)+(wireMap.width*g);
786		type[g]= FindTypeForKey(xkb,None,wireMap.width,tmpSyms);
787	    }
788	    xkb->map->key_sym_map[i].kt_index[g]= type[g]-(&xkb->map->types[0]);
789	}
790	xkb->map->key_sym_map[i].group_info= wireMap.num_groups;
791	xkb->map->key_sym_map[i].width= wireMap.width;
792	if (wireMap.flags&XkmKeyHasBehavior) {
793	    xkmBehaviorDesc	b;
794	    tmp= fread(&b,SIZEOF(xkmBehaviorDesc),1,file);
795	    nRead+= tmp*SIZEOF(xkmBehaviorDesc);
796	    xkb->server->behaviors[i].type= b.type;
797	    xkb->server->behaviors[i].data= b.data;
798	    xkb->server->explicit[i]|= XkbExplicitBehaviorMask;
799	}
800    }
801    if (totalVModMaps>0) {
802	xkmVModMapDesc	v;
803	for (i=0;i<totalVModMaps;i++) {
804	    tmp= fread(&v,SIZEOF(xkmVModMapDesc),1,file);
805	    nRead+= tmp*SIZEOF(xkmVModMapDesc);
806	    if (tmp>0)
807		xkb->server->vmodmap[v.key]= v.vmods;
808	}
809    }
810    return nRead;
811}
812
813static int
814ReadXkmGeomDoodad(
815    FILE *		file,
816    XkbGeometryPtr	geom,
817    XkbSectionPtr	section)
818{
819XkbDoodadPtr	doodad;
820xkmDoodadDesc	doodadWire;
821char		buf[100];
822unsigned	tmp;
823int		nRead=0;
824
825    nRead+= XkmGetCountedString(file,buf,100);
826    tmp= fread(&doodadWire,SIZEOF(xkmDoodadDesc),1,file);
827    nRead+= SIZEOF(xkmDoodadDesc)*tmp;
828    doodad= XkbAddGeomDoodad(geom,section,XkbInternAtom(buf,FALSE));
829    if (!doodad)
830	return nRead;
831    doodad->any.type= doodadWire.any.type;
832    doodad->any.priority= doodadWire.any.priority;
833    doodad->any.top= doodadWire.any.top;
834    doodad->any.left= doodadWire.any.left;
835    switch (doodadWire.any.type) {
836	case XkbOutlineDoodad:
837	case XkbSolidDoodad:
838	    doodad->shape.angle= doodadWire.shape.angle;
839	    doodad->shape.color_ndx= doodadWire.shape.color_ndx;
840	    doodad->shape.shape_ndx= doodadWire.shape.shape_ndx;
841	    break;
842	case XkbTextDoodad:
843	    doodad->text.angle= doodadWire.text.angle;
844	    doodad->text.width= doodadWire.text.width;
845	    doodad->text.height= doodadWire.text.height;
846	    doodad->text.color_ndx= doodadWire.text.color_ndx;
847	    nRead+= XkmGetCountedString(file,buf,100);
848	    doodad->text.text= _XkbDupString(buf);
849	    nRead+= XkmGetCountedString(file,buf,100);
850	    doodad->text.font= _XkbDupString(buf);
851	    break;
852	case XkbIndicatorDoodad:
853	    doodad->indicator.shape_ndx= doodadWire.indicator.shape_ndx;
854	    doodad->indicator.on_color_ndx= doodadWire.indicator.on_color_ndx;
855	    doodad->indicator.off_color_ndx= doodadWire.indicator.off_color_ndx;
856	    break;
857	case XkbLogoDoodad:
858	    doodad->logo.angle= doodadWire.logo.angle;
859	    doodad->logo.color_ndx= doodadWire.logo.color_ndx;
860	    doodad->logo.shape_ndx= doodadWire.logo.shape_ndx;
861	    nRead+= XkmGetCountedString(file,buf,100);
862	    doodad->logo.logo_name= _XkbDupString(buf);
863	    break;
864	default:
865	    /* report error? */
866	    return nRead;
867    }
868    return nRead;
869}
870
871static int
872ReadXkmGeomOverlay(	FILE *		file,
873			XkbGeometryPtr	geom,
874			XkbSectionPtr	section)
875{
876char 			buf[100];
877unsigned		tmp;
878int			nRead=0;
879XkbOverlayPtr		ol;
880XkbOverlayRowPtr	row;
881xkmOverlayDesc 		olWire;
882xkmOverlayRowDesc	rowWire;
883register int		r;
884
885    nRead+= XkmGetCountedString(file,buf,100);
886    tmp= fread(&olWire,SIZEOF(xkmOverlayDesc),1,file);
887    nRead+= tmp*SIZEOF(xkmOverlayDesc);
888    ol= XkbAddGeomOverlay(section,XkbInternAtom(buf,FALSE),
889    							olWire.num_rows);
890    if (!ol)
891	return nRead;
892    for (r=0;r<olWire.num_rows;r++)  {
893    	int			k;
894	xkmOverlayKeyDesc	keyWire;
895	tmp= fread(&rowWire,SIZEOF(xkmOverlayRowDesc),1,file);
896	nRead+= tmp*SIZEOF(xkmOverlayRowDesc);
897	row= XkbAddGeomOverlayRow(ol,rowWire.row_under,rowWire.num_keys);
898	if (!row) {
899	    _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomOverlay",0);
900	   return nRead;
901	}
902	for (k=0;k<rowWire.num_keys;k++) {
903	    tmp= fread(&keyWire,SIZEOF(xkmOverlayKeyDesc),1,file);
904	    nRead+= tmp*SIZEOF(xkmOverlayKeyDesc);
905	    memcpy(row->keys[k].over.name,keyWire.over,XkbKeyNameLength);
906	    memcpy(row->keys[k].under.name,keyWire.under,XkbKeyNameLength);
907	}
908	row->num_keys= rowWire.num_keys;
909    }
910    return nRead;
911}
912
913static int
914ReadXkmGeomSection(	FILE *		file,
915			XkbGeometryPtr	geom)
916{
917register int	i;
918XkbSectionPtr	section;
919xkmSectionDesc	sectionWire;
920unsigned	tmp;
921int		nRead= 0;
922char		buf[100];
923Atom		nameAtom;
924
925    nRead+= XkmGetCountedString(file,buf,100);
926    nameAtom= XkbInternAtom(buf,FALSE);
927    tmp= fread(&sectionWire,SIZEOF(xkmSectionDesc),1,file);
928    nRead+= SIZEOF(xkmSectionDesc)*tmp;
929    section= XkbAddGeomSection(geom,nameAtom,sectionWire.num_rows,
930			 			sectionWire.num_doodads,
931			 			sectionWire.num_overlays);
932    if (!section) {
933	_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0);
934	return nRead;
935    }
936    section->top= sectionWire.top;
937    section->left= sectionWire.left;
938    section->width= sectionWire.width;
939    section->height= sectionWire.height;
940    section->angle= sectionWire.angle;
941    section->priority= sectionWire.priority;
942    if (sectionWire.num_rows>0) {
943	register int	k;
944	XkbRowPtr	row;
945	xkmRowDesc	rowWire;
946	XkbKeyPtr	key;
947	xkmKeyDesc	keyWire;
948
949	for (i=0;i<sectionWire.num_rows;i++) {
950	    tmp= fread(&rowWire,SIZEOF(xkmRowDesc),1,file);
951	    nRead+= SIZEOF(xkmRowDesc)*tmp;
952	    row= XkbAddGeomRow(section,rowWire.num_keys);
953	    if (!row) {
954		_XkbLibError(_XkbErrBadAlloc,"ReadXkmKeycodes",0);
955		return nRead;
956	    }
957	    row->top= rowWire.top;
958	    row->left= rowWire.left;
959	    row->vertical= rowWire.vertical;
960	    for (k=0;k<rowWire.num_keys;k++) {
961		tmp= fread(&keyWire,SIZEOF(xkmKeyDesc),1,file);
962		nRead+= SIZEOF(xkmKeyDesc)*tmp;
963		key= XkbAddGeomKey(row);
964		if (!key) {
965		    _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeomSection",0);
966		    return nRead;
967		}
968		memcpy(key->name.name,keyWire.name,XkbKeyNameLength);
969		key->gap= keyWire.gap;
970		key->shape_ndx= keyWire.shape_ndx;
971		key->color_ndx= keyWire.color_ndx;
972	    }
973	}
974    }
975    if (sectionWire.num_doodads>0) {
976	for (i=0;i<sectionWire.num_doodads;i++) {
977	    tmp= ReadXkmGeomDoodad(file,geom,section);
978	    nRead+= tmp;
979	    if (tmp<1)
980		return nRead;
981	}
982    }
983    if (sectionWire.num_overlays>0) {
984	for (i=0;i<sectionWire.num_overlays;i++) {
985	    tmp= ReadXkmGeomOverlay(file,geom,section);
986	    nRead+= tmp;
987	    if (tmp<1)
988		return nRead;
989	}
990    }
991    return nRead;
992}
993
994static int
995ReadXkmGeometry(FILE *file,XkbDescPtr xkb)
996{
997register int		i;
998char 			buf[100];
999unsigned		tmp;
1000int			nRead= 0;
1001xkmGeometryDesc		wireGeom;
1002XkbGeometryPtr		geom;
1003XkbGeometrySizesRec	sizes;
1004
1005    nRead+= XkmGetCountedString(file,buf,100);
1006    tmp= fread(&wireGeom,SIZEOF(xkmGeometryDesc),1,file);
1007    nRead+= tmp*SIZEOF(xkmGeometryDesc);
1008    sizes.which= XkbGeomAllMask;
1009    sizes.num_properties= wireGeom.num_properties;
1010    sizes.num_colors= wireGeom.num_colors;
1011    sizes.num_shapes= wireGeom.num_shapes;
1012    sizes.num_sections= wireGeom.num_sections;
1013    sizes.num_doodads= wireGeom.num_doodads;
1014    sizes.num_key_aliases= wireGeom.num_key_aliases;
1015    if (XkbAllocGeometry(xkb,&sizes)!=Success) {
1016	_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
1017	return nRead;
1018    }
1019    geom= xkb->geom;
1020    geom->name= XkbInternAtom(buf,FALSE);
1021    geom->width_mm= wireGeom.width_mm;
1022    geom->height_mm= wireGeom.height_mm;
1023    nRead+= XkmGetCountedString(file,buf,100);
1024    geom->label_font= _XkbDupString(buf);
1025    if (wireGeom.num_properties>0) {
1026	char val[1024];
1027	for (i=0;i<wireGeom.num_properties;i++) {
1028	    nRead+= XkmGetCountedString(file,buf,100);
1029	    nRead+= XkmGetCountedString(file,val,1024);
1030	    if (XkbAddGeomProperty(geom,buf,val)==NULL) {
1031		_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
1032		return nRead;
1033	    }
1034	}
1035    }
1036    if (wireGeom.num_colors>0) {
1037	for (i=0;i<wireGeom.num_colors;i++) {
1038	    nRead+= XkmGetCountedString(file,buf,100);
1039	    if (XkbAddGeomColor(geom,buf,i)==NULL) {
1040		_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
1041		return nRead;
1042	    }
1043	}
1044    }
1045    geom->base_color= &geom->colors[wireGeom.base_color_ndx];
1046    geom->label_color= &geom->colors[wireGeom.label_color_ndx];
1047    if (wireGeom.num_shapes>0) {
1048	XkbShapePtr	shape;
1049	xkmShapeDesc	shapeWire;
1050	Atom		nameAtom;
1051	for (i=0;i<wireGeom.num_shapes;i++) {
1052	    register int 	n;
1053	    XkbOutlinePtr	ol;
1054	    xkmOutlineDesc	olWire;
1055	    nRead+= XkmGetCountedString(file,buf,100);
1056	    nameAtom= XkbInternAtom(buf,FALSE);
1057	    tmp= fread(&shapeWire,SIZEOF(xkmShapeDesc),1,file);
1058	    nRead+= tmp*SIZEOF(xkmShapeDesc);
1059	    shape= XkbAddGeomShape(geom,nameAtom,shapeWire.num_outlines);
1060	    if (!shape) {
1061		_XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
1062		return nRead;
1063	    }
1064	    for (n=0;n<shapeWire.num_outlines;n++) {
1065		register int	p;
1066		xkmPointDesc	ptWire;
1067		tmp= fread(&olWire,SIZEOF(xkmOutlineDesc),1,file);
1068		nRead+= tmp*SIZEOF(xkmOutlineDesc);
1069		ol= XkbAddGeomOutline(shape,olWire.num_points);
1070		if (!ol) {
1071		    _XkbLibError(_XkbErrBadAlloc,"ReadXkmGeometry",0);
1072		    return nRead;
1073		}
1074		ol->num_points= olWire.num_points;
1075		ol->corner_radius= olWire.corner_radius;
1076		for (p=0;p<olWire.num_points;p++) {
1077		    tmp= fread(&ptWire,SIZEOF(xkmPointDesc),1,file);
1078		    nRead+= tmp*SIZEOF(xkmPointDesc);
1079		    ol->points[p].x= ptWire.x;
1080		    ol->points[p].y= ptWire.y;
1081		    if (ptWire.x<shape->bounds.x1) shape->bounds.x1= ptWire.x;
1082		    if (ptWire.x>shape->bounds.x2) shape->bounds.x2= ptWire.x;
1083		    if (ptWire.y<shape->bounds.y1) shape->bounds.y1= ptWire.y;
1084		    if (ptWire.y>shape->bounds.y2) shape->bounds.y2= ptWire.y;
1085		}
1086	    }
1087	    if (shapeWire.primary_ndx!=XkbNoShape)
1088		shape->primary= &shape->outlines[shapeWire.primary_ndx];
1089	    if (shapeWire.approx_ndx!=XkbNoShape)
1090		shape->approx= &shape->outlines[shapeWire.approx_ndx];
1091	}
1092    }
1093    if (wireGeom.num_sections>0) {
1094	for (i=0;i<wireGeom.num_sections;i++) {
1095	    tmp= ReadXkmGeomSection(file,geom);
1096	    nRead+= tmp;
1097	    if (tmp==0)
1098		return nRead;
1099	}
1100    }
1101    if (wireGeom.num_doodads>0) {
1102	for (i=0;i<wireGeom.num_doodads;i++) {
1103	    tmp= ReadXkmGeomDoodad(file,geom,NULL);
1104	    nRead+= tmp;
1105	    if (tmp==0)
1106		return nRead;
1107	}
1108    }
1109    if ((wireGeom.num_key_aliases>0)&&(geom->key_aliases)) {
1110	int sz= XkbKeyNameLength*2;
1111	int num= wireGeom.num_key_aliases;
1112	if (fread(geom->key_aliases,sz,num,file)!=num) {
1113	    _XkbLibError(_XkbErrBadLength,"ReadXkmGeometry",0);
1114	    return -1;
1115	}
1116	nRead+= (num*sz);
1117	geom->num_key_aliases= num;
1118    }
1119    return nRead;
1120}
1121
1122Bool
1123XkmProbe(FILE *file)
1124{
1125unsigned hdr,tmp;
1126int	 nRead=0;
1127
1128    hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion);
1129    tmp= XkmGetCARD32(file,&nRead);
1130    if (tmp!=hdr) {
1131	if ((tmp&(~0xff))==(hdr&(~0xff))) {
1132	    _XkbLibError(_XkbErrBadFileVersion,"XkmProbe",tmp&0xff);
1133	}
1134	return 0;
1135    }
1136    return 1;
1137}
1138
1139static Bool
1140XkmReadTOC(FILE *file,xkmFileInfo* file_info,int max_toc,xkmSectionInfo *toc)
1141{
1142unsigned hdr,tmp;
1143int	nRead=0;
1144unsigned i,size_toc;
1145
1146    hdr= (('x'<<24)|('k'<<16)|('m'<<8)|XkmFileVersion);
1147    tmp= XkmGetCARD32(file,&nRead);
1148    if (tmp!=hdr) {
1149	if ((tmp&(~0xff))==(hdr&(~0xff))) {
1150	    _XkbLibError(_XkbErrBadFileVersion,"XkmReadTOC",tmp&0xff);
1151	}
1152	else {
1153	    _XkbLibError(_XkbErrBadFileType,"XkmReadTOC",tmp);
1154	}
1155	return 0;
1156    }
1157    fread(file_info,SIZEOF(xkmFileInfo),1,file);
1158    size_toc= file_info->num_toc;
1159    if (size_toc>max_toc) {
1160	DebugF("Warning! Too many TOC entries; last %d ignored\n",
1161							size_toc-max_toc);
1162	size_toc= max_toc;
1163    }
1164    for (i=0;i<size_toc;i++) {
1165	fread(&toc[i],SIZEOF(xkmSectionInfo),1,file);
1166    }
1167    return 1;
1168}
1169
1170/***====================================================================***/
1171
1172#define	MAX_TOC	16
1173unsigned
1174XkmReadFile(FILE *file,unsigned need,unsigned want,XkbDescPtr *xkb)
1175{
1176register unsigned	i;
1177xkmSectionInfo		toc[MAX_TOC],tmpTOC;
1178xkmFileInfo		fileInfo;
1179unsigned		tmp,nRead=0;
1180unsigned		which= need|want;
1181
1182    if (!XkmReadTOC(file,&fileInfo,MAX_TOC,toc))
1183	return which;
1184    if ((fileInfo.present&need)!=need) {
1185       _XkbLibError(_XkbErrIllegalContents,"XkmReadFile",
1186       						need&(~fileInfo.present));
1187       return which;
1188    }
1189    if (*xkb==NULL)
1190	*xkb= XkbAllocKeyboard();
1191    for (i=0;i<fileInfo.num_toc;i++) {
1192	fseek(file,toc[i].offset,SEEK_SET);
1193	tmp= fread(&tmpTOC,SIZEOF(xkmSectionInfo),1,file);
1194	nRead= tmp*SIZEOF(xkmSectionInfo);
1195	if ((tmpTOC.type!=toc[i].type)||(tmpTOC.format!=toc[i].format)||
1196	    (tmpTOC.size!=toc[i].size)||(tmpTOC.offset!=toc[i].offset)) {
1197	    return which;
1198	}
1199	if ((which&(1<<tmpTOC.type))==0) {
1200	    continue;
1201	}
1202	switch (tmpTOC.type) {
1203	    case XkmVirtualModsIndex:
1204		tmp= ReadXkmVirtualMods(file,*xkb,NULL);
1205		break;
1206	    case XkmTypesIndex:
1207		tmp= ReadXkmKeyTypes(file,*xkb,NULL);
1208		break;
1209	    case XkmCompatMapIndex:
1210		tmp= ReadXkmCompatMap(file,*xkb,NULL);
1211		break;
1212	    case XkmKeyNamesIndex:
1213		tmp= ReadXkmKeycodes(file,*xkb,NULL);
1214		break;
1215	    case XkmIndicatorsIndex:
1216		tmp= ReadXkmIndicators(file,*xkb,NULL);
1217		break;
1218	    case XkmSymbolsIndex:
1219		tmp= ReadXkmSymbols(file,*xkb);
1220		break;
1221	    case XkmGeometryIndex:
1222		tmp= ReadXkmGeometry(file,*xkb);
1223		break;
1224	    default:
1225		_XkbLibError(_XkbErrBadImplementation,
1226				XkbConfigText(tmpTOC.type,XkbMessage),0);
1227		tmp= 0;
1228		break;
1229	}
1230	if (tmp>0) {
1231	    nRead+= tmp;
1232	    which&= ~(1<<toc[i].type);
1233	    (*xkb)->defined|= (1<<toc[i].type);
1234	}
1235	if (nRead!=tmpTOC.size) {
1236	    _XkbLibError(_XkbErrBadLength,XkbConfigText(tmpTOC.type,XkbMessage),
1237	    						nRead-tmpTOC.size);
1238	}
1239    }
1240    return which;
1241}
1242