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