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