initial commit
[profile/ivi/xorg-x11-server.git] / xkb / xkmread.c
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
46 Atom
47 XkbInternAtom(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
54 char *
55 _XkbDupString(const char *str)
56 {
57 char *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
69 static void *
70 XkmInsureSize(void *oldPtr,int oldCount,int *newCountRtrn,int elemSize)
71 {
72 int     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
94 static CARD8
95 XkmGetCARD8(FILE *file,int *pNRead)
96 {
97 int     tmp;
98     tmp= getc(file);
99     if (pNRead&&(tmp!=EOF))
100         (*pNRead)+= 1;
101     return tmp;
102 }
103
104 static CARD16
105 XkmGetCARD16(FILE *file,int *pNRead)
106 {
107 CARD16          val;
108
109     if ((fread(&val,2,1,file)==1)&&(pNRead))
110         (*pNRead)+= 2;
111     return val;
112 }
113
114 static CARD32
115 XkmGetCARD32(FILE *file,int *pNRead)
116 {
117 CARD32  val;
118
119     if ((fread(&val,4,1,file)==1)&&(pNRead))
120         (*pNRead)+= 4;
121     return val;
122 }
123
124 static int
125 XkmSkipPadding(FILE *file,unsigned pad)
126 {
127 register 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
136 static int
137 XkmGetCountedString(FILE *file,char *str,int max_len)
138 {
139 int     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
167 static int
168 ReadXkmVirtualMods(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
169 {
170 register unsigned int i,bit;
171 unsigned int    bound,named,tmp;
172 int             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
209 static int
210 ReadXkmKeycodes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
211 {
212 register int    i;
213 unsigned        minKC,maxKC,nAl;
214 int             nRead=0;
215 char            name[100];
216 XkbKeyNamePtr   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
274 static int
275 ReadXkmKeyTypes(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
276 {
277 register unsigned       i,n;
278 unsigned                num_types;
279 int                     nRead=0;
280 int                     tmp;
281 XkbKeyTypePtr           type;
282 xkmKeyTypeDesc          wire;
283 XkbKTMapEntryPtr        entry;
284 xkmKTMapEntryDesc       wire_entry;
285 char                    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
410 static int
411 ReadXkmCompatMap(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
412 {
413 register int            i;
414 unsigned                num_si,groups;
415 char                    name[100];
416 XkbSymInterpretPtr      interp;
417 xkmSymInterpretDesc     wire;
418 unsigned                tmp;
419 int                     nRead=0;
420 XkbCompatMapPtr         compat;
421 XkbAction               *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
576 static int
577 ReadXkmIndicators(FILE *file,XkbDescPtr xkb,XkbChangesPtr changes)
578 {
579 register unsigned       nLEDs;
580 xkmIndicatorMapDesc     wire;
581 char                    buf[100];
582 unsigned                tmp;
583 int                     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
631 static XkbKeyTypePtr
632 FindTypeForKey(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
657 static int
658 ReadXkmSymbols(FILE *file,XkbDescPtr xkb)
659 {
660 register int            i,g,s,totalVModMaps;
661 xkmKeySymMapDesc        wireMap;
662 char                    buf[100];
663 unsigned                minKC,maxKC,groupNames,tmp;
664 int                     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
810 static int
811 ReadXkmGeomDoodad(
812     FILE *              file,
813     XkbGeometryPtr      geom,
814     XkbSectionPtr       section)
815 {
816 XkbDoodadPtr    doodad;
817 xkmDoodadDesc   doodadWire;
818 char            buf[100];
819 unsigned        tmp;
820 int             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
868 static int
869 ReadXkmGeomOverlay(     FILE *          file,
870                         XkbGeometryPtr  geom,
871                         XkbSectionPtr   section)
872 {
873 char                    buf[100];
874 unsigned                tmp;
875 int                     nRead=0;
876 XkbOverlayPtr           ol;
877 XkbOverlayRowPtr        row;
878 xkmOverlayDesc          olWire;
879 xkmOverlayRowDesc       rowWire;
880 register 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
910 static int
911 ReadXkmGeomSection(     FILE *          file,
912                         XkbGeometryPtr  geom)
913 {
914 register int    i;
915 XkbSectionPtr   section;
916 xkmSectionDesc  sectionWire;
917 unsigned        tmp;
918 int             nRead= 0;
919 char            buf[100];
920 Atom            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
991 static int
992 ReadXkmGeometry(FILE *file,XkbDescPtr xkb)
993 {
994 register int            i;
995 char                    buf[100];
996 unsigned                tmp;
997 int                     nRead= 0;
998 xkmGeometryDesc         wireGeom;
999 XkbGeometryPtr          geom;
1000 XkbGeometrySizesRec     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
1119 Bool
1120 XkmProbe(FILE *file)
1121 {
1122 unsigned hdr,tmp;
1123 int      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
1136 static Bool
1137 XkmReadTOC(FILE *file,xkmFileInfo* file_info,int max_toc,xkmSectionInfo *toc)
1138 {
1139 unsigned hdr,tmp;
1140 int     nRead=0;
1141 unsigned 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
1170 unsigned
1171 XkmReadFile(FILE *file,unsigned need,unsigned want,XkbDescPtr *xkb)
1172 {
1173 register unsigned       i;
1174 xkmSectionInfo          toc[MAX_TOC],tmpTOC;
1175 xkmFileInfo             fileInfo;
1176 unsigned                tmp,nRead=0;
1177 unsigned                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 }