Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /************************************************************ |
2 | Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. | |
3 | ||
4 | Permission to use, copy, modify, and distribute this | |
5 | software and its documentation for any purpose and without | |
6 | fee is hereby granted, provided that the above copyright | |
7 | notice appear in all copies and that both that copyright | |
8 | notice and this permission notice appear in supporting | |
9 | documentation, and that the name of Silicon Graphics not be | |
10 | used in advertising or publicity pertaining to distribution | |
11 | of the software without specific prior written permission. | |
12 | Silicon Graphics makes no representation about the suitability | |
13 | of this software for any purpose. It is provided "as is" | |
14 | without any express or implied warranty. | |
15 | ||
16 | SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS | |
17 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |
18 | AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON | |
19 | GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL | |
20 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
21 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |
22 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH | |
23 | THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
24 | ||
25 | ********************************************************/ | |
26 | ||
27 | #ifdef HAVE_DIX_CONFIG_H | |
28 | #include <dix-config.h> | |
29 | #endif | |
30 | ||
31 | #include <stdio.h> | |
32 | ||
33 | #include <X11/Xos.h> | |
34 | #include <X11/Xfuncs.h> | |
35 | ||
36 | #include <X11/X.h> | |
37 | #include <X11/Xproto.h> | |
38 | #include <X11/keysym.h> | |
39 | #include <X11/extensions/XKMformat.h> | |
40 | #include "misc.h" | |
41 | #include "inputstr.h" | |
42 | #include "xkbstr.h" | |
43 | #include "xkbsrv.h" | |
44 | #include "xkbgeom.h" | |
45 | ||
46 | Atom | |
47 | XkbInternAtom(char *str, Bool only_if_exists) | |
48 | { | |
49 | if (str == NULL) | |
50 | return None; | |
51 | return MakeAtom(str, strlen(str), !only_if_exists); | |
52 | } | |
53 | ||
54 | /***====================================================================***/ | |
55 | ||
56 | static void * | |
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 = realloc(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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | fread(file_info, SIZEOF(xkmFileInfo), 1, file); | |
1208 | size_toc = file_info->num_toc; | |
1209 | if (size_toc > max_toc) { | |
1210 | DebugF("Warning! Too many TOC entries; last %d ignored\n", | |
1211 | size_toc - max_toc); | |
1212 | size_toc = max_toc; | |
1213 | } | |
1214 | for (i = 0; i < size_toc; i++) { | |
1215 | fread(&toc[i], SIZEOF(xkmSectionInfo), 1, file); | |
1216 | } | |
1217 | return 1; | |
1218 | } | |
1219 | ||
1220 | /***====================================================================***/ | |
1221 | ||
1222 | #define MAX_TOC 16 | |
1223 | unsigned | |
1224 | XkmReadFile(FILE * file, unsigned need, unsigned want, XkbDescPtr *xkb) | |
1225 | { | |
1226 | register unsigned i; | |
1227 | xkmSectionInfo toc[MAX_TOC], tmpTOC; | |
1228 | xkmFileInfo fileInfo; | |
1229 | unsigned tmp, nRead = 0; | |
1230 | unsigned which = need | want; | |
1231 | ||
1232 | if (!XkmReadTOC(file, &fileInfo, MAX_TOC, toc)) | |
1233 | return which; | |
1234 | if ((fileInfo.present & need) != need) { | |
1235 | _XkbLibError(_XkbErrIllegalContents, "XkmReadFile", | |
1236 | need & (~fileInfo.present)); | |
1237 | return which; | |
1238 | } | |
1239 | if (*xkb == NULL) | |
1240 | *xkb = XkbAllocKeyboard(); | |
1241 | for (i = 0; i < fileInfo.num_toc; i++) { | |
1242 | fseek(file, toc[i].offset, SEEK_SET); | |
1243 | tmp = fread(&tmpTOC, SIZEOF(xkmSectionInfo), 1, file); | |
1244 | nRead = tmp * SIZEOF(xkmSectionInfo); | |
1245 | if ((tmpTOC.type != toc[i].type) || (tmpTOC.format != toc[i].format) || | |
1246 | (tmpTOC.size != toc[i].size) || (tmpTOC.offset != toc[i].offset)) { | |
1247 | return which; | |
1248 | } | |
1249 | if ((which & (1 << tmpTOC.type)) == 0) { | |
1250 | continue; | |
1251 | } | |
1252 | switch (tmpTOC.type) { | |
1253 | case XkmVirtualModsIndex: | |
1254 | tmp = ReadXkmVirtualMods(file, *xkb, NULL); | |
1255 | break; | |
1256 | case XkmTypesIndex: | |
1257 | tmp = ReadXkmKeyTypes(file, *xkb, NULL); | |
1258 | break; | |
1259 | case XkmCompatMapIndex: | |
1260 | tmp = ReadXkmCompatMap(file, *xkb, NULL); | |
1261 | break; | |
1262 | case XkmKeyNamesIndex: | |
1263 | tmp = ReadXkmKeycodes(file, *xkb, NULL); | |
1264 | break; | |
1265 | case XkmIndicatorsIndex: | |
1266 | tmp = ReadXkmIndicators(file, *xkb, NULL); | |
1267 | break; | |
1268 | case XkmSymbolsIndex: | |
1269 | tmp = ReadXkmSymbols(file, *xkb); | |
1270 | break; | |
1271 | case XkmGeometryIndex: | |
1272 | tmp = ReadXkmGeometry(file, *xkb); | |
1273 | break; | |
1274 | default: | |
1275 | _XkbLibError(_XkbErrBadImplementation, | |
1276 | XkbConfigText(tmpTOC.type, XkbMessage), 0); | |
1277 | tmp = 0; | |
1278 | break; | |
1279 | } | |
1280 | if (tmp > 0) { | |
1281 | nRead += tmp; | |
1282 | which &= ~(1 << toc[i].type); | |
1283 | (*xkb)->defined |= (1 << toc[i].type); | |
1284 | } | |
1285 | if (nRead != tmpTOC.size) { | |
1286 | _XkbLibError(_XkbErrBadLength, | |
1287 | XkbConfigText(tmpTOC.type, XkbMessage), | |
1288 | nRead - tmpTOC.size); | |
1289 | } | |
1290 | } | |
1291 | return which; | |
1292 | } |