| 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 | } |