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