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(§ionWire, 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