1278 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1278 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
| /************************************************************
 | |
|  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
 | |
| 
 | |
|  Permission to use, copy, modify, and distribute this
 | |
|  software and its documentation for any purpose and without
 | |
|  fee is hereby granted, provided that the above copyright
 | |
|  notice appear in all copies and that both that copyright
 | |
|  notice and this permission notice appear in supporting
 | |
|  documentation, and that the name of Silicon Graphics not be
 | |
|  used in advertising or publicity pertaining to distribution
 | |
|  of the software without specific prior written permission.
 | |
|  Silicon Graphics makes no representation about the suitability
 | |
|  of this software for any purpose. It is provided "as is"
 | |
|  without any express or implied warranty.
 | |
| 
 | |
|  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 | |
|  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 | |
|  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
 | |
|  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 | |
|  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 | |
|  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
 | |
|  THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
|  ********************************************************/
 | |
| 
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <X11/Xos.h>
 | |
| #include <X11/Xfuncs.h>
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include <X11/keysym.h>
 | |
| #include <X11/extensions/XKMformat.h>
 | |
| 
 | |
| #include "xkb/xkbfile_priv.h"
 | |
| #include "xkb/xkbfmisc_priv.h"
 | |
| #include "xkb/xkbsrv_priv.h"
 | |
| 
 | |
| #include "misc.h"
 | |
| #include "inputstr.h"
 | |
| #include "xkbstr.h"
 | |
| #include "xkbgeom.h"
 | |
| 
 | |
| static Atom
 | |
| XkbInternAtom(char *str, Bool only_if_exists)
 | |
| {
 | |
|     if (str == NULL)
 | |
|         return None;
 | |
|     return MakeAtom(str, strlen(str), !only_if_exists);
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static void *
 | |
| XkmInsureSize(void *oldPtr, int oldCount, int *newCountRtrn, int elemSize)
 | |
| {
 | |
|     int newCount = *newCountRtrn;
 | |
| 
 | |
|     if (oldPtr == NULL) {
 | |
|         if (newCount == 0)
 | |
|             return NULL;
 | |
|         oldPtr = calloc(newCount, elemSize);
 | |
|     }
 | |
|     else if (oldCount < newCount) {
 | |
|         oldPtr = reallocarray(oldPtr, newCount, elemSize);
 | |
|         if (oldPtr != NULL) {
 | |
|             char *tmp = (char *) oldPtr;
 | |
| 
 | |
|             memset(&tmp[oldCount * elemSize], 0,
 | |
|                    (newCount - oldCount) * elemSize);
 | |
|         }
 | |
|     }
 | |
|     else if (newCount < oldCount) {
 | |
|         *newCountRtrn = oldCount;
 | |
|     }
 | |
|     return oldPtr;
 | |
| }
 | |
| 
 | |
| #define	XkmInsureTypedSize(p,o,n,t) ((p)=((t *)XkmInsureSize((char *)(p),(o),(n),sizeof(t))))
 | |
| 
 | |
| static CARD8
 | |
| XkmGetCARD8(FILE * file, int *pNRead)
 | |
| {
 | |
|     int tmp;
 | |
| 
 | |
|     tmp = getc(file);
 | |
|     if (pNRead && (tmp != EOF))
 | |
|         (*pNRead) += 1;
 | |
|     return tmp;
 | |
| }
 | |
| 
 | |
| static CARD16
 | |
| XkmGetCARD16(FILE * file, int *pNRead)
 | |
| {
 | |
|     CARD16 val;
 | |
| 
 | |
|     if ((fread(&val, 2, 1, file) == 1) && (pNRead))
 | |
|         (*pNRead) += 2;
 | |
|     return val;
 | |
| }
 | |
| 
 | |
| static CARD32
 | |
| XkmGetCARD32(FILE * file, int *pNRead)
 | |
| {
 | |
|     CARD32 val;
 | |
| 
 | |
|     if ((fread(&val, 4, 1, file) == 1) && (pNRead))
 | |
|         (*pNRead) += 4;
 | |
|     return val;
 | |
| }
 | |
| 
 | |
| static int
 | |
| XkmSkipPadding(FILE * file, unsigned pad)
 | |
| {
 | |
|     register int i, nRead = 0;
 | |
| 
 | |
|     for (i = 0; i < pad; i++) {
 | |
|         if (getc(file) != EOF)
 | |
|             nRead++;
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static int
 | |
| XkmGetCountedString(FILE * file, char *str, int max_len)
 | |
| {
 | |
|     int count, nRead = 0;
 | |
| 
 | |
|     count = XkmGetCARD16(file, &nRead);
 | |
|     if (count > 0) {
 | |
|         int tmp;
 | |
| 
 | |
|         if (count > max_len) {
 | |
|             tmp = fread(str, 1, max_len, file);
 | |
|             while (tmp < count) {
 | |
|                 if ((getc(file)) != EOF)
 | |
|                     tmp++;
 | |
|                 else
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             tmp = fread(str, 1, count, file);
 | |
|         }
 | |
|         nRead += tmp;
 | |
|     }
 | |
|     if (count >= max_len)
 | |
|         str[max_len - 1] = '\0';
 | |
|     else
 | |
|         str[count] = '\0';
 | |
|     count = XkbPaddedSize(nRead) - nRead;
 | |
|     if (count > 0)
 | |
|         nRead += XkmSkipPadding(file, count);
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static int
 | |
| ReadXkmVirtualMods(FILE * file, XkbDescPtr xkb, XkbChangesPtr changes)
 | |
| {
 | |
|     register unsigned int i, bit;
 | |
|     unsigned int bound, named, tmp;
 | |
|     int nRead = 0;
 | |
| 
 | |
|     if (XkbAllocServerMap(xkb, XkbVirtualModsMask, 0) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "ReadXkmVirtualMods", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     bound = XkmGetCARD16(file, &nRead);
 | |
|     named = XkmGetCARD16(file, &nRead);
 | |
|     for (i = tmp = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
 | |
|         if (bound & bit) {
 | |
|             xkb->server->vmods[i] = XkmGetCARD8(file, &nRead);
 | |
|             if (changes)
 | |
|                 changes->map.vmods |= bit;
 | |
|             tmp++;
 | |
|         }
 | |
|     }
 | |
|     if ((i = XkbPaddedSize(tmp) - tmp) > 0)
 | |
|         nRead += XkmSkipPadding(file, i);
 | |
|     if (XkbAllocNames(xkb, XkbVirtualModNamesMask, 0, 0) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "ReadXkmVirtualMods", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
 | |
|         char name[100];
 | |
| 
 | |
|         if (named & bit) {
 | |
|             if (nRead += XkmGetCountedString(file, name, 100)) {
 | |
|                 xkb->names->vmods[i] = XkbInternAtom(name, FALSE);
 | |
|                 if (changes)
 | |
|                     changes->names.changed_vmods |= bit;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static int
 | |
| ReadXkmKeycodes(FILE * file, XkbDescPtr xkb, XkbChangesPtr changes)
 | |
| {
 | |
|     register int i;
 | |
|     unsigned minKC, maxKC, nAl;
 | |
|     int nRead = 0;
 | |
|     char name[100];
 | |
|     XkbKeyNamePtr pN;
 | |
| 
 | |
|     name[0] = '\0';
 | |
|     nRead += XkmGetCountedString(file, name, 100);
 | |
|     minKC = XkmGetCARD8(file, &nRead);
 | |
|     maxKC = XkmGetCARD8(file, &nRead);
 | |
|     if (xkb->min_key_code == 0) {
 | |
|         xkb->min_key_code = minKC;
 | |
|         xkb->max_key_code = maxKC;
 | |
|     }
 | |
|     else {
 | |
|         if (minKC < xkb->min_key_code)
 | |
|             xkb->min_key_code = minKC;
 | |
|         if (maxKC > xkb->max_key_code) {
 | |
|             _XkbLibError(_XkbErrBadValue, "ReadXkmKeycodes", maxKC);
 | |
|             return -1;
 | |
|         }
 | |
|     }
 | |
|     nAl = XkmGetCARD8(file, &nRead);
 | |
|     nRead += XkmSkipPadding(file, 1);
 | |
| 
 | |
| #define WANTED (XkbKeycodesNameMask|XkbKeyNamesMask|XkbKeyAliasesMask)
 | |
|     if (XkbAllocNames(xkb, WANTED, 0, nAl) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "ReadXkmKeycodes", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     if (name[0] != '\0') {
 | |
|         xkb->names->keycodes = XkbInternAtom(name, FALSE);
 | |
|     }
 | |
| 
 | |
|     for (pN = &xkb->names->keys[minKC], i = minKC; i <= (int) maxKC; i++, pN++) {
 | |
|         if (fread(pN, 1, XkbKeyNameLength, file) != XkbKeyNameLength) {
 | |
|             _XkbLibError(_XkbErrBadLength, "ReadXkmKeycodes", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         nRead += XkbKeyNameLength;
 | |
|     }
 | |
|     if (nAl > 0) {
 | |
|         XkbKeyAliasPtr pAl;
 | |
| 
 | |
|         for (pAl = xkb->names->key_aliases, i = 0; i < nAl; i++, pAl++) {
 | |
|             int tmp;
 | |
| 
 | |
|             tmp = fread(pAl, 1, 2 * XkbKeyNameLength, file);
 | |
|             if (tmp != 2 * XkbKeyNameLength) {
 | |
|                 _XkbLibError(_XkbErrBadLength, "ReadXkmKeycodes", 0);
 | |
|                 return -1;
 | |
|             }
 | |
|             nRead += 2 * XkbKeyNameLength;
 | |
|         }
 | |
|         if (changes)
 | |
|             changes->names.changed |= XkbKeyAliasesMask;
 | |
|     }
 | |
|     if (changes)
 | |
|         changes->names.changed |= XkbKeyNamesMask;
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static int
 | |
| ReadXkmKeyTypes(FILE * file, XkbDescPtr xkb, XkbChangesPtr changes)
 | |
| {
 | |
|     register unsigned i, n;
 | |
|     unsigned num_types;
 | |
|     int nRead = 0;
 | |
|     int tmp;
 | |
|     XkbKeyTypePtr type;
 | |
|     xkmKeyTypeDesc wire;
 | |
|     XkbKTMapEntryPtr entry;
 | |
|     xkmKTMapEntryDesc wire_entry;
 | |
|     char buf[100];
 | |
| 
 | |
|     if ((tmp = XkmGetCountedString(file, buf, 100)) < 1) {
 | |
|         _XkbLibError(_XkbErrBadLength, "ReadXkmKeyTypes", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     nRead += tmp;
 | |
|     if (buf[0] != '\0') {
 | |
|         if (XkbAllocNames(xkb, XkbTypesNameMask, 0, 0) != Success) {
 | |
|             _XkbLibError(_XkbErrBadAlloc, "ReadXkmKeyTypes", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         xkb->names->types = XkbInternAtom(buf, FALSE);
 | |
|     }
 | |
|     num_types = XkmGetCARD16(file, &nRead);
 | |
|     nRead += XkmSkipPadding(file, 2);
 | |
|     if (num_types < 1)
 | |
|         return nRead;
 | |
|     if (XkbAllocClientMap(xkb, XkbKeyTypesMask, num_types) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "ReadXkmKeyTypes", 0);
 | |
|         return nRead;
 | |
|     }
 | |
|     xkb->map->num_types = num_types;
 | |
|     if (num_types < XkbNumRequiredTypes) {
 | |
|         _XkbLibError(_XkbErrMissingReqTypes, "ReadXkmKeyTypes", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     type = xkb->map->types;
 | |
|     for (i = 0; i < num_types; i++, type++) {
 | |
|         if ((int) fread(&wire, SIZEOF(xkmKeyTypeDesc), 1, file) < 1) {
 | |
|             _XkbLibError(_XkbErrBadLength, "ReadXkmKeyTypes", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         nRead += SIZEOF(xkmKeyTypeDesc);
 | |
|         if (((i == XkbOneLevelIndex) && (wire.numLevels != 1)) ||
 | |
|             (((i == XkbTwoLevelIndex) || (i == XkbAlphabeticIndex) ||
 | |
|               ((i) == XkbKeypadIndex)) && (wire.numLevels != 2))) {
 | |
|             _XkbLibError(_XkbErrBadTypeWidth, "ReadXkmKeyTypes", i);
 | |
|             return -1;
 | |
|         }
 | |
|         tmp = wire.nMapEntries;
 | |
|         XkmInsureTypedSize(type->map, type->map_count, &tmp, XkbKTMapEntryRec);
 | |
|         if ((wire.nMapEntries > 0) && (type->map == NULL)) {
 | |
|             _XkbLibError(_XkbErrBadValue, "ReadXkmKeyTypes", wire.nMapEntries);
 | |
|             return -1;
 | |
|         }
 | |
|         for (n = 0, entry = type->map; n < wire.nMapEntries; n++, entry++) {
 | |
|             if (fread(&wire_entry, SIZEOF(xkmKTMapEntryDesc), 1, file) <
 | |
|                 (int) 1) {
 | |
|                 _XkbLibError(_XkbErrBadLength, "ReadXkmKeyTypes", 0);
 | |
|                 return -1;
 | |
|             }
 | |
|             nRead += SIZEOF(xkmKTMapEntryDesc);
 | |
|             entry->active = (wire_entry.virtualMods == 0);
 | |
|             entry->level = wire_entry.level;
 | |
|             entry->mods.mask = wire_entry.realMods;
 | |
|             entry->mods.real_mods = wire_entry.realMods;
 | |
|             entry->mods.vmods = wire_entry.virtualMods;
 | |
|         }
 | |
|         nRead += XkmGetCountedString(file, buf, 100);
 | |
|         if (((i == XkbOneLevelIndex) && (strcmp(buf, "ONE_LEVEL") != 0)) ||
 | |
|             ((i == XkbTwoLevelIndex) && (strcmp(buf, "TWO_LEVEL") != 0)) ||
 | |
|             ((i == XkbAlphabeticIndex) && (strcmp(buf, "ALPHABETIC") != 0)) ||
 | |
|             ((i == XkbKeypadIndex) && (strcmp(buf, "KEYPAD") != 0))) {
 | |
|             _XkbLibError(_XkbErrBadTypeName, "ReadXkmKeyTypes", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         if (buf[0] != '\0') {
 | |
|             type->name = XkbInternAtom(buf, FALSE);
 | |
|         }
 | |
|         else
 | |
|             type->name = None;
 | |
| 
 | |
|         if (wire.preserve) {
 | |
|             xkmModsDesc p_entry;
 | |
|             XkbModsPtr pre;
 | |
| 
 | |
|             XkmInsureTypedSize(type->preserve, type->map_count, &tmp,
 | |
|                                XkbModsRec);
 | |
|             if (type->preserve == NULL) {
 | |
|                 _XkbLibError(_XkbErrBadMatch, "ReadXkmKeycodes", 0);
 | |
|                 return -1;
 | |
|             }
 | |
|             for (n = 0, pre = type->preserve; n < wire.nMapEntries; n++, pre++) {
 | |
|                 if (fread(&p_entry, SIZEOF(xkmModsDesc), 1, file) < 1) {
 | |
|                     _XkbLibError(_XkbErrBadLength, "ReadXkmKeycodes", 0);
 | |
|                     return -1;
 | |
|                 }
 | |
|                 nRead += SIZEOF(xkmModsDesc);
 | |
|                 pre->mask = p_entry.realMods;
 | |
|                 pre->real_mods = p_entry.realMods;
 | |
|                 pre->vmods = p_entry.virtualMods;
 | |
|             }
 | |
|         }
 | |
|         if (wire.nLevelNames > 0) {
 | |
|             int width = wire.numLevels;
 | |
| 
 | |
|             if (wire.nLevelNames > (unsigned) width) {
 | |
|                 _XkbLibError(_XkbErrBadMatch, "ReadXkmKeycodes", 0);
 | |
|                 return -1;
 | |
|             }
 | |
|             XkmInsureTypedSize(type->level_names, type->num_levels, &width,
 | |
|                                Atom);
 | |
|             if (type->level_names != NULL) {
 | |
|                 for (n = 0; n < wire.nLevelNames; n++) {
 | |
|                     if ((tmp = XkmGetCountedString(file, buf, 100)) < 1)
 | |
|                         return -1;
 | |
|                     nRead += tmp;
 | |
|                     if (strlen(buf) == 0)
 | |
|                         type->level_names[n] = None;
 | |
|                     else
 | |
|                         type->level_names[n] = XkbInternAtom(buf, 0);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         type->mods.mask = wire.realMods;
 | |
|         type->mods.real_mods = wire.realMods;
 | |
|         type->mods.vmods = wire.virtualMods;
 | |
|         type->num_levels = wire.numLevels;
 | |
|         type->map_count = wire.nMapEntries;
 | |
|     }
 | |
|     if (changes) {
 | |
|         changes->map.changed |= XkbKeyTypesMask;
 | |
|         changes->map.first_type = 0;
 | |
|         changes->map.num_types = xkb->map->num_types;
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static int
 | |
| ReadXkmCompatMap(FILE * file, XkbDescPtr xkb, XkbChangesPtr changes)
 | |
| {
 | |
|     register int i;
 | |
|     unsigned num_si, groups;
 | |
|     char name[100];
 | |
|     XkbSymInterpretPtr interp;
 | |
|     xkmSymInterpretDesc wire;
 | |
|     unsigned tmp;
 | |
|     int nRead = 0;
 | |
|     XkbCompatMapPtr compat;
 | |
|     XkbAction *act;
 | |
| 
 | |
|     if ((tmp = XkmGetCountedString(file, name, 100)) < 1) {
 | |
|         _XkbLibError(_XkbErrBadLength, "ReadXkmCompatMap", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     nRead += tmp;
 | |
|     if (name[0] != '\0') {
 | |
|         if (XkbAllocNames(xkb, XkbCompatNameMask, 0, 0) != Success) {
 | |
|             _XkbLibError(_XkbErrBadAlloc, "ReadXkmCompatMap", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         xkb->names->compat = XkbInternAtom(name, FALSE);
 | |
|     }
 | |
|     num_si = XkmGetCARD16(file, &nRead);
 | |
|     groups = XkmGetCARD8(file, &nRead);
 | |
|     nRead += XkmSkipPadding(file, 1);
 | |
|     if (XkbAllocCompatMap(xkb, XkbAllCompatMask, num_si) != Success)
 | |
|         return -1;
 | |
|     compat = xkb->compat;
 | |
|     compat->num_si = 0;
 | |
|     interp = compat->sym_interpret;
 | |
|     for (i = 0; i < num_si; i++) {
 | |
|         tmp = fread(&wire, SIZEOF(xkmSymInterpretDesc), 1, file);
 | |
|         nRead += tmp * SIZEOF(xkmSymInterpretDesc);
 | |
|         interp->sym = wire.sym;
 | |
|         interp->mods = wire.mods;
 | |
|         interp->match = wire.match;
 | |
|         interp->virtual_mod = wire.virtualMod;
 | |
|         interp->flags = wire.flags;
 | |
|         interp->act.type = wire.actionType;
 | |
|         act = (XkbAction *) &interp->act;
 | |
| 
 | |
|         switch (interp->act.type) {
 | |
|         case XkbSA_SetMods:
 | |
|         case XkbSA_LatchMods:
 | |
|         case XkbSA_LockMods:
 | |
|             act->mods.flags = wire.actionData[0];
 | |
|             act->mods.mask = wire.actionData[1];
 | |
|             act->mods.real_mods = wire.actionData[2];
 | |
|             act->mods.vmods1 = wire.actionData[3];
 | |
|             act->mods.vmods2 = wire.actionData[4];
 | |
|             break;
 | |
|         case XkbSA_SetGroup:
 | |
|         case XkbSA_LatchGroup:
 | |
|         case XkbSA_LockGroup:
 | |
|             act->group.flags = wire.actionData[0];
 | |
|             act->group.group_XXX = wire.actionData[1];
 | |
|             break;
 | |
|         case XkbSA_MovePtr:
 | |
|             act->ptr.flags = wire.actionData[0];
 | |
|             act->ptr.high_XXX = wire.actionData[1];
 | |
|             act->ptr.low_XXX = wire.actionData[2];
 | |
|             act->ptr.high_YYY = wire.actionData[3];
 | |
|             act->ptr.low_YYY = wire.actionData[4];
 | |
|             break;
 | |
|         case XkbSA_PtrBtn:
 | |
|         case XkbSA_LockPtrBtn:
 | |
|             act->btn.flags = wire.actionData[0];
 | |
|             act->btn.count = wire.actionData[1];
 | |
|             act->btn.button = wire.actionData[2];
 | |
|             break;
 | |
|         case XkbSA_DeviceBtn:
 | |
|         case XkbSA_LockDeviceBtn:
 | |
|             act->devbtn.flags = wire.actionData[0];
 | |
|             act->devbtn.count = wire.actionData[1];
 | |
|             act->devbtn.button = wire.actionData[2];
 | |
|             act->devbtn.device = wire.actionData[3];
 | |
|             break;
 | |
|         case XkbSA_SetPtrDflt:
 | |
|             act->dflt.flags = wire.actionData[0];
 | |
|             act->dflt.affect = wire.actionData[1];
 | |
|             act->dflt.valueXXX = wire.actionData[2];
 | |
|             break;
 | |
|         case XkbSA_ISOLock:
 | |
|             act->iso.flags = wire.actionData[0];
 | |
|             act->iso.mask = wire.actionData[1];
 | |
|             act->iso.real_mods = wire.actionData[2];
 | |
|             act->iso.group_XXX = wire.actionData[3];
 | |
|             act->iso.affect = wire.actionData[4];
 | |
|             act->iso.vmods1 = wire.actionData[5];
 | |
|             act->iso.vmods2 = wire.actionData[6];
 | |
|             break;
 | |
|         case XkbSA_SwitchScreen:
 | |
|             act->screen.flags = wire.actionData[0];
 | |
|             act->screen.screenXXX = wire.actionData[1];
 | |
|             break;
 | |
|         case XkbSA_SetControls:
 | |
|         case XkbSA_LockControls:
 | |
|             act->ctrls.flags = wire.actionData[0];
 | |
|             act->ctrls.ctrls3 = wire.actionData[1];
 | |
|             act->ctrls.ctrls2 = wire.actionData[2];
 | |
|             act->ctrls.ctrls1 = wire.actionData[3];
 | |
|             act->ctrls.ctrls0 = wire.actionData[4];
 | |
|             break;
 | |
|         case XkbSA_RedirectKey:
 | |
|             act->redirect.new_key = wire.actionData[0];
 | |
|             act->redirect.mods_mask = wire.actionData[1];
 | |
|             act->redirect.mods = wire.actionData[2];
 | |
|             act->redirect.vmods_mask0 = wire.actionData[3];
 | |
|             act->redirect.vmods_mask1 = wire.actionData[4];
 | |
|             act->redirect.vmods0 = wire.actionData[4];
 | |
|             act->redirect.vmods1 = wire.actionData[5];
 | |
|             break;
 | |
|         case XkbSA_DeviceValuator:
 | |
|             act->devval.device = wire.actionData[0];
 | |
|             act->devval.v1_what = wire.actionData[1];
 | |
|             act->devval.v1_ndx = wire.actionData[2];
 | |
|             act->devval.v1_value = wire.actionData[3];
 | |
|             act->devval.v2_what = wire.actionData[4];
 | |
|             act->devval.v2_ndx = wire.actionData[5];
 | |
|             act->devval.v2_value = wire.actionData[6];
 | |
|             break;
 | |
| 
 | |
|         case XkbSA_XFree86Private:
 | |
|             /*
 | |
|              * Bugfix for broken xkbcomp: if we encounter an XFree86Private
 | |
|              * action with Any+AnyOfOrNone(All), then we skip the interp as
 | |
|              * broken.  Versions of xkbcomp below 1.2.2 had a bug where they
 | |
|              * would interpret a symbol that couldn't be found in an interpret
 | |
|              * as Any.  So, an XF86LogWindowTree+AnyOfOrNone(All) interp that
 | |
|              * triggered the PrWins action would make every key without an
 | |
|              * action trigger PrWins if libX11 didn't yet know about the
 | |
|              * XF86LogWindowTree keysym.  None too useful.
 | |
|              *
 | |
|              * We only do this for XFree86 actions, as the current XKB
 | |
|              * dataset relies on Any+AnyOfOrNone(All) -> SetMods for Ctrl in
 | |
|              * particular.
 | |
|              *
 | |
|              * See xkbcomp commits 2a473b906943ffd807ad81960c47530ee7ae9a60 and
 | |
|              * 3caab5aa37decb7b5dc1642a0452efc3e1f5100e for more details.
 | |
|              */
 | |
|             if (interp->sym == NoSymbol && interp->match == XkbSI_AnyOfOrNone &&
 | |
|                 (interp->mods & 0xff) == 0xff) {
 | |
|                 ErrorF("XKB: Skipping broken Any+AnyOfOrNone(All) -> Private "
 | |
|                        "action from compiled keymap\n");
 | |
|                 continue;
 | |
|             }
 | |
|             /* copy the kind of action */
 | |
|             memcpy(act->any.data, wire.actionData, XkbAnyActionDataSize);
 | |
|             break;
 | |
| 
 | |
|         case XkbSA_Terminate:
 | |
|             /* no args, kinda (note: untrue for xfree86). */
 | |
|             break;
 | |
|         case XkbSA_ActionMessage:
 | |
|             /* unsupported. */
 | |
|             break;
 | |
|         }
 | |
|         interp++;
 | |
|         compat->num_si++;
 | |
|     }
 | |
|     if ((num_si > 0) && (changes)) {
 | |
|         changes->compat.first_si = 0;
 | |
|         changes->compat.num_si = compat->num_si;
 | |
|     }
 | |
|     if (groups) {
 | |
|         register unsigned bit;
 | |
| 
 | |
|         for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
 | |
|             xkmModsDesc md;
 | |
| 
 | |
|             if (groups & bit) {
 | |
|                 tmp = fread(&md, SIZEOF(xkmModsDesc), 1, file);
 | |
|                 nRead += tmp * SIZEOF(xkmModsDesc);
 | |
|                 xkb->compat->groups[i].real_mods = md.realMods;
 | |
|                 xkb->compat->groups[i].vmods = md.virtualMods;
 | |
|                 if (md.virtualMods != 0) {
 | |
|                     unsigned mask;
 | |
| 
 | |
|                     if (XkbVirtualModsToReal(xkb, md.virtualMods, &mask))
 | |
|                         xkb->compat->groups[i].mask = md.realMods | mask;
 | |
|                 }
 | |
|                 else
 | |
|                     xkb->compat->groups[i].mask = md.realMods;
 | |
|             }
 | |
|         }
 | |
|         if (changes)
 | |
|             changes->compat.changed_groups |= groups;
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ReadXkmIndicators(FILE * file, XkbDescPtr xkb, XkbChangesPtr changes)
 | |
| {
 | |
|     register unsigned nLEDs;
 | |
|     xkmIndicatorMapDesc wire;
 | |
|     char buf[100];
 | |
|     unsigned tmp;
 | |
|     int nRead = 0;
 | |
| 
 | |
|     if ((xkb->indicators == NULL) && (XkbAllocIndicatorMaps(xkb) != Success)) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "indicator rec", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     if (XkbAllocNames(xkb, XkbIndicatorNamesMask, 0, 0) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "indicator names", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     nLEDs = XkmGetCARD8(file, &nRead);
 | |
|     nRead += XkmSkipPadding(file, 3);
 | |
|     xkb->indicators->phys_indicators = XkmGetCARD32(file, &nRead);
 | |
|     while (nLEDs-- > 0) {
 | |
|         Atom name;
 | |
|         XkbIndicatorMapPtr map;
 | |
| 
 | |
|         if ((tmp = XkmGetCountedString(file, buf, 100)) < 1) {
 | |
|             _XkbLibError(_XkbErrBadLength, "ReadXkmIndicators", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         nRead += tmp;
 | |
|         if (buf[0] != '\0')
 | |
|             name = XkbInternAtom(buf, FALSE);
 | |
|         else
 | |
|             name = None;
 | |
|         if ((tmp = fread(&wire, SIZEOF(xkmIndicatorMapDesc), 1, file)) < 1) {
 | |
|             _XkbLibError(_XkbErrBadLength, "ReadXkmIndicators", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         nRead += tmp * SIZEOF(xkmIndicatorMapDesc);
 | |
|         if (xkb->names) {
 | |
|             xkb->names->indicators[wire.indicator - 1] = name;
 | |
|             if (changes)
 | |
|                 changes->names.changed_indicators |=
 | |
|                     (1 << (wire.indicator - 1));
 | |
|         }
 | |
|         map = &xkb->indicators->maps[wire.indicator - 1];
 | |
|         map->flags = wire.flags;
 | |
|         map->which_groups = wire.which_groups;
 | |
|         map->groups = wire.groups;
 | |
|         map->which_mods = wire.which_mods;
 | |
|         map->mods.mask = wire.real_mods;
 | |
|         map->mods.real_mods = wire.real_mods;
 | |
|         map->mods.vmods = wire.vmods;
 | |
|         map->ctrls = wire.ctrls;
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static XkbKeyTypePtr
 | |
| FindTypeForKey(XkbDescPtr xkb, Atom name, unsigned width, KeySym * syms)
 | |
| {
 | |
|     if ((!xkb) || (!xkb->map))
 | |
|         return NULL;
 | |
|     if (name != None) {
 | |
|         register unsigned i;
 | |
| 
 | |
|         for (i = 0; i < xkb->map->num_types; i++) {
 | |
|             if (xkb->map->types[i].name == name) {
 | |
|                 if (xkb->map->types[i].num_levels != width)
 | |
|                     DebugF("Group width mismatch between key and type\n");
 | |
|                 return &xkb->map->types[i];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if ((width < 2) || ((syms != NULL) && (syms[1] == NoSymbol)))
 | |
|         return &xkb->map->types[XkbOneLevelIndex];
 | |
|     if (syms != NULL) {
 | |
|         if (XkbKSIsLower(syms[0]) && XkbKSIsUpper(syms[1]))
 | |
|             return &xkb->map->types[XkbAlphabeticIndex];
 | |
|         else if (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1]))
 | |
|             return &xkb->map->types[XkbKeypadIndex];
 | |
|     }
 | |
|     return &xkb->map->types[XkbTwoLevelIndex];
 | |
| }
 | |
| 
 | |
| static int
 | |
| ReadXkmSymbols(FILE * file, XkbDescPtr xkb)
 | |
| {
 | |
|     register int i, g, s, totalVModMaps;
 | |
|     xkmKeySymMapDesc wireMap;
 | |
|     char buf[100];
 | |
|     unsigned minKC, maxKC, groupNames, tmp;
 | |
|     int nRead = 0;
 | |
| 
 | |
|     if ((tmp = XkmGetCountedString(file, buf, 100)) < 1)
 | |
|         return -1;
 | |
|     nRead += tmp;
 | |
|     minKC = XkmGetCARD8(file, &nRead);
 | |
|     maxKC = XkmGetCARD8(file, &nRead);
 | |
|     groupNames = XkmGetCARD8(file, &nRead);
 | |
|     totalVModMaps = XkmGetCARD8(file, &nRead);
 | |
|     if (XkbAllocNames(xkb,
 | |
|                       XkbSymbolsNameMask | XkbPhysSymbolsNameMask |
 | |
|                       XkbGroupNamesMask, 0, 0) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "physical names", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     if ((buf[0] != '\0') && (xkb->names)) {
 | |
|         Atom name;
 | |
| 
 | |
|         name = XkbInternAtom(buf, 0);
 | |
|         xkb->names->symbols = name;
 | |
|         xkb->names->phys_symbols = name;
 | |
|     }
 | |
|     for (i = 0, g = 1; i < XkbNumKbdGroups; i++, g <<= 1) {
 | |
|         if (groupNames & g) {
 | |
|             if ((tmp = XkmGetCountedString(file, buf, 100)) < 1)
 | |
|                 return -1;
 | |
|             nRead += tmp;
 | |
| 
 | |
|             if (!xkb->names)
 | |
|                 continue;
 | |
| 
 | |
|             if (buf[0] != '\0') {
 | |
|                 Atom name;
 | |
| 
 | |
|                 name = XkbInternAtom(buf, 0);
 | |
|                 xkb->names->groups[i] = name;
 | |
|             }
 | |
|             else
 | |
|                 xkb->names->groups[i] = None;
 | |
|         }
 | |
|     }
 | |
|     if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 0) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "server map", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     if (XkbAllocClientMap(xkb, XkbAllClientInfoMask, 0) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "client map", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     if (XkbAllocControls(xkb, XkbAllControlsMask) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "controls", 0);
 | |
|         return -1;
 | |
|     }
 | |
|     if ((xkb->map == NULL) || (xkb->server == NULL))
 | |
|         return -1;
 | |
|     if (xkb->min_key_code < 8)
 | |
|         xkb->min_key_code = minKC;
 | |
|     if (xkb->max_key_code < 8)
 | |
|         xkb->max_key_code = maxKC;
 | |
|     if ((minKC >= 8) && (minKC < xkb->min_key_code))
 | |
|         xkb->min_key_code = minKC;
 | |
|     if ((maxKC >= 8) && (maxKC > xkb->max_key_code)) {
 | |
|         _XkbLibError(_XkbErrBadValue, "keys in symbol map", maxKC);
 | |
|         return -1;
 | |
|     }
 | |
|     for (i = minKC; i <= (int) maxKC; i++) {
 | |
|         Atom typeName[XkbNumKbdGroups];
 | |
|         XkbKeyTypePtr type[XkbNumKbdGroups];
 | |
| 
 | |
|         if ((tmp = fread(&wireMap, SIZEOF(xkmKeySymMapDesc), 1, file)) < 1) {
 | |
|             _XkbLibError(_XkbErrBadLength, "ReadXkmSymbols", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         nRead += tmp * SIZEOF(xkmKeySymMapDesc);
 | |
|         memset((char *) typeName, 0, XkbNumKbdGroups * sizeof(Atom));
 | |
|         memset((char *) type, 0, XkbNumKbdGroups * sizeof(XkbKeyTypePtr));
 | |
|         if (wireMap.flags & XkmKeyHasTypes) {
 | |
|             for (g = 0; g < XkbNumKbdGroups; g++) {
 | |
|                 if ((wireMap.flags & (1 << g)) &&
 | |
|                     ((tmp = XkmGetCountedString(file, buf, 100)) > 0)) {
 | |
|                     typeName[g] = XkbInternAtom(buf, 1);
 | |
|                     nRead += tmp;
 | |
|                 }
 | |
|                 type[g] = FindTypeForKey(xkb, typeName[g], wireMap.width, NULL);
 | |
|                 if (type[g] == NULL) {
 | |
|                     _XkbLibError(_XkbErrMissingTypes, "ReadXkmSymbols", 0);
 | |
|                     return -1;
 | |
|                 }
 | |
|                 if (typeName[g] == type[g]->name)
 | |
|                     xkb->server->explicit[i] |= (1 << g);
 | |
|             }
 | |
|         }
 | |
|         if (wireMap.flags & XkmRepeatingKey) {
 | |
|             xkb->ctrls->per_key_repeat[i / 8] |= (1 << (i % 8));
 | |
|             xkb->server->explicit[i] |= XkbExplicitAutoRepeatMask;
 | |
|         }
 | |
|         else if (wireMap.flags & XkmNonRepeatingKey) {
 | |
|             xkb->ctrls->per_key_repeat[i / 8] &= ~(1 << (i % 8));
 | |
|             xkb->server->explicit[i] |= XkbExplicitAutoRepeatMask;
 | |
|         }
 | |
|         xkb->map->modmap[i] = wireMap.modifier_map;
 | |
|         if (XkbNumGroups(wireMap.num_groups) > 0) {
 | |
|             KeySym *sym;
 | |
|             int nSyms;
 | |
| 
 | |
|             if (XkbNumGroups(wireMap.num_groups) > xkb->ctrls->num_groups)
 | |
|                 xkb->ctrls->num_groups = wireMap.num_groups;
 | |
|             nSyms = XkbNumGroups(wireMap.num_groups) * wireMap.width;
 | |
|             sym = XkbResizeKeySyms(xkb, i, nSyms);
 | |
|             if (!sym)
 | |
|                 return -1;
 | |
|             for (s = 0; s < nSyms; s++) {
 | |
|                 *sym++ = XkmGetCARD32(file, &nRead);
 | |
|             }
 | |
|             if (wireMap.flags & XkmKeyHasActions) {
 | |
|                 XkbAction *act;
 | |
| 
 | |
|                 act = XkbResizeKeyActions(xkb, i, nSyms);
 | |
|                 for (s = 0; s < nSyms; s++, act++) {
 | |
|                     tmp = fread(act, SIZEOF(xkmActionDesc), 1, file);
 | |
|                     nRead += tmp * SIZEOF(xkmActionDesc);
 | |
|                 }
 | |
|                 xkb->server->explicit[i] |= XkbExplicitInterpretMask;
 | |
|             }
 | |
|         }
 | |
|         for (g = 0; g < XkbNumGroups(wireMap.num_groups); g++) {
 | |
|             if (((xkb->server->explicit[i] & (1 << g)) == 0) ||
 | |
|                 (type[g] == NULL)) {
 | |
|                 KeySym *tmpSyms;
 | |
| 
 | |
|                 tmpSyms = XkbKeySymsPtr(xkb, i) + (wireMap.width * g);
 | |
|                 type[g] = FindTypeForKey(xkb, None, wireMap.width, tmpSyms);
 | |
|             }
 | |
|             xkb->map->key_sym_map[i].kt_index[g] =
 | |
|                 type[g] - (&xkb->map->types[0]);
 | |
|         }
 | |
|         xkb->map->key_sym_map[i].group_info = wireMap.num_groups;
 | |
|         xkb->map->key_sym_map[i].width = wireMap.width;
 | |
|         if (wireMap.flags & XkmKeyHasBehavior) {
 | |
|             xkmBehaviorDesc b;
 | |
| 
 | |
|             tmp = fread(&b, SIZEOF(xkmBehaviorDesc), 1, file);
 | |
|             nRead += tmp * SIZEOF(xkmBehaviorDesc);
 | |
|             xkb->server->behaviors[i].type = b.type;
 | |
|             xkb->server->behaviors[i].data = b.data;
 | |
|             xkb->server->explicit[i] |= XkbExplicitBehaviorMask;
 | |
|         }
 | |
|     }
 | |
|     if (totalVModMaps > 0) {
 | |
|         xkmVModMapDesc v;
 | |
| 
 | |
|         for (i = 0; i < totalVModMaps; i++) {
 | |
|             tmp = fread(&v, SIZEOF(xkmVModMapDesc), 1, file);
 | |
|             nRead += tmp * SIZEOF(xkmVModMapDesc);
 | |
|             if (tmp > 0)
 | |
|                 xkb->server->vmodmap[v.key] = v.vmods;
 | |
|         }
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ReadXkmGeomDoodad(FILE * file, XkbGeometryPtr geom, XkbSectionPtr section)
 | |
| {
 | |
|     XkbDoodadPtr doodad;
 | |
|     xkmDoodadDesc doodadWire;
 | |
|     char buf[100];
 | |
|     unsigned tmp;
 | |
|     int nRead = 0;
 | |
| 
 | |
|     nRead += XkmGetCountedString(file, buf, 100);
 | |
|     tmp = fread(&doodadWire, SIZEOF(xkmDoodadDesc), 1, file);
 | |
|     nRead += SIZEOF(xkmDoodadDesc) * tmp;
 | |
|     doodad = XkbAddGeomDoodad(geom, section, XkbInternAtom(buf, FALSE));
 | |
|     if (!doodad)
 | |
|         return nRead;
 | |
|     doodad->any.type = doodadWire.any.type;
 | |
|     doodad->any.priority = doodadWire.any.priority;
 | |
|     doodad->any.top = doodadWire.any.top;
 | |
|     doodad->any.left = doodadWire.any.left;
 | |
|     switch (doodadWire.any.type) {
 | |
|     case XkbOutlineDoodad:
 | |
|     case XkbSolidDoodad:
 | |
|         doodad->shape.angle = doodadWire.shape.angle;
 | |
|         doodad->shape.color_ndx = doodadWire.shape.color_ndx;
 | |
|         doodad->shape.shape_ndx = doodadWire.shape.shape_ndx;
 | |
|         break;
 | |
|     case XkbTextDoodad:
 | |
|         doodad->text.angle = doodadWire.text.angle;
 | |
|         doodad->text.width = doodadWire.text.width;
 | |
|         doodad->text.height = doodadWire.text.height;
 | |
|         doodad->text.color_ndx = doodadWire.text.color_ndx;
 | |
|         nRead += XkmGetCountedString(file, buf, 100);
 | |
|         doodad->text.text = Xstrdup(buf);
 | |
|         nRead += XkmGetCountedString(file, buf, 100);
 | |
|         doodad->text.font = Xstrdup(buf);
 | |
|         break;
 | |
|     case XkbIndicatorDoodad:
 | |
|         doodad->indicator.shape_ndx = doodadWire.indicator.shape_ndx;
 | |
|         doodad->indicator.on_color_ndx = doodadWire.indicator.on_color_ndx;
 | |
|         doodad->indicator.off_color_ndx = doodadWire.indicator.off_color_ndx;
 | |
|         break;
 | |
|     case XkbLogoDoodad:
 | |
|         doodad->logo.angle = doodadWire.logo.angle;
 | |
|         doodad->logo.color_ndx = doodadWire.logo.color_ndx;
 | |
|         doodad->logo.shape_ndx = doodadWire.logo.shape_ndx;
 | |
|         nRead += XkmGetCountedString(file, buf, 100);
 | |
|         doodad->logo.logo_name = Xstrdup(buf);
 | |
|         break;
 | |
|     default:
 | |
|         /* report error? */
 | |
|         return nRead;
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ReadXkmGeomOverlay(FILE * file, XkbGeometryPtr geom, XkbSectionPtr section)
 | |
| {
 | |
|     char buf[100];
 | |
|     unsigned tmp;
 | |
|     int nRead = 0;
 | |
|     XkbOverlayPtr ol;
 | |
|     XkbOverlayRowPtr row;
 | |
|     xkmOverlayDesc olWire;
 | |
|     xkmOverlayRowDesc rowWire;
 | |
|     register int r;
 | |
| 
 | |
|     nRead += XkmGetCountedString(file, buf, 100);
 | |
|     tmp = fread(&olWire, SIZEOF(xkmOverlayDesc), 1, file);
 | |
|     nRead += tmp * SIZEOF(xkmOverlayDesc);
 | |
|     ol = XkbAddGeomOverlay(section, XkbInternAtom(buf, FALSE), olWire.num_rows);
 | |
|     if (!ol)
 | |
|         return nRead;
 | |
|     for (r = 0; r < olWire.num_rows; r++) {
 | |
|         int k;
 | |
|         xkmOverlayKeyDesc keyWire;
 | |
| 
 | |
|         tmp = fread(&rowWire, SIZEOF(xkmOverlayRowDesc), 1, file);
 | |
|         nRead += tmp * SIZEOF(xkmOverlayRowDesc);
 | |
|         row = XkbAddGeomOverlayRow(ol, rowWire.row_under, rowWire.num_keys);
 | |
|         if (!row) {
 | |
|             _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeomOverlay", 0);
 | |
|             return nRead;
 | |
|         }
 | |
|         for (k = 0; k < rowWire.num_keys; k++) {
 | |
|             tmp = fread(&keyWire, SIZEOF(xkmOverlayKeyDesc), 1, file);
 | |
|             nRead += tmp * SIZEOF(xkmOverlayKeyDesc);
 | |
|             memcpy(row->keys[k].over.name, keyWire.over, XkbKeyNameLength);
 | |
|             memcpy(row->keys[k].under.name, keyWire.under, XkbKeyNameLength);
 | |
|         }
 | |
|         row->num_keys = rowWire.num_keys;
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ReadXkmGeomSection(FILE * file, XkbGeometryPtr geom)
 | |
| {
 | |
|     register int i;
 | |
|     XkbSectionPtr section;
 | |
|     xkmSectionDesc sectionWire;
 | |
|     unsigned tmp;
 | |
|     int nRead = 0;
 | |
|     char buf[100];
 | |
|     Atom nameAtom;
 | |
| 
 | |
|     nRead += XkmGetCountedString(file, buf, 100);
 | |
|     nameAtom = XkbInternAtom(buf, FALSE);
 | |
|     tmp = fread(§ionWire, SIZEOF(xkmSectionDesc), 1, file);
 | |
|     nRead += SIZEOF(xkmSectionDesc) * tmp;
 | |
|     section = XkbAddGeomSection(geom, nameAtom, sectionWire.num_rows,
 | |
|                                 sectionWire.num_doodads,
 | |
|                                 sectionWire.num_overlays);
 | |
|     if (!section) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeomSection", 0);
 | |
|         return nRead;
 | |
|     }
 | |
|     section->top = sectionWire.top;
 | |
|     section->left = sectionWire.left;
 | |
|     section->width = sectionWire.width;
 | |
|     section->height = sectionWire.height;
 | |
|     section->angle = sectionWire.angle;
 | |
|     section->priority = sectionWire.priority;
 | |
|     if (sectionWire.num_rows > 0) {
 | |
|         register int k;
 | |
|         XkbRowPtr row;
 | |
|         xkmRowDesc rowWire;
 | |
|         XkbKeyPtr key;
 | |
|         xkmKeyDesc keyWire;
 | |
| 
 | |
|         for (i = 0; i < sectionWire.num_rows; i++) {
 | |
|             tmp = fread(&rowWire, SIZEOF(xkmRowDesc), 1, file);
 | |
|             nRead += SIZEOF(xkmRowDesc) * tmp;
 | |
|             row = XkbAddGeomRow(section, rowWire.num_keys);
 | |
|             if (!row) {
 | |
|                 _XkbLibError(_XkbErrBadAlloc, "ReadXkmKeycodes", 0);
 | |
|                 return nRead;
 | |
|             }
 | |
|             row->top = rowWire.top;
 | |
|             row->left = rowWire.left;
 | |
|             row->vertical = rowWire.vertical;
 | |
|             for (k = 0; k < rowWire.num_keys; k++) {
 | |
|                 tmp = fread(&keyWire, SIZEOF(xkmKeyDesc), 1, file);
 | |
|                 nRead += SIZEOF(xkmKeyDesc) * tmp;
 | |
|                 key = XkbAddGeomKey(row);
 | |
|                 if (!key) {
 | |
|                     _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeomSection", 0);
 | |
|                     return nRead;
 | |
|                 }
 | |
|                 memcpy(key->name.name, keyWire.name, XkbKeyNameLength);
 | |
|                 key->gap = keyWire.gap;
 | |
|                 key->shape_ndx = keyWire.shape_ndx;
 | |
|                 key->color_ndx = keyWire.color_ndx;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if (sectionWire.num_doodads > 0) {
 | |
|         for (i = 0; i < sectionWire.num_doodads; i++) {
 | |
|             tmp = ReadXkmGeomDoodad(file, geom, section);
 | |
|             nRead += tmp;
 | |
|             if (tmp < 1)
 | |
|                 return nRead;
 | |
|         }
 | |
|     }
 | |
|     if (sectionWire.num_overlays > 0) {
 | |
|         for (i = 0; i < sectionWire.num_overlays; i++) {
 | |
|             tmp = ReadXkmGeomOverlay(file, geom, section);
 | |
|             nRead += tmp;
 | |
|             if (tmp < 1)
 | |
|                 return nRead;
 | |
|         }
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ReadXkmGeometry(FILE * file, XkbDescPtr xkb)
 | |
| {
 | |
|     register int i;
 | |
|     char buf[100];
 | |
|     unsigned tmp;
 | |
|     int nRead = 0;
 | |
|     xkmGeometryDesc wireGeom;
 | |
|     XkbGeometryPtr geom;
 | |
|     XkbGeometrySizesRec sizes;
 | |
| 
 | |
|     nRead += XkmGetCountedString(file, buf, 100);
 | |
|     tmp = fread(&wireGeom, SIZEOF(xkmGeometryDesc), 1, file);
 | |
|     nRead += tmp * SIZEOF(xkmGeometryDesc);
 | |
|     sizes.which = XkbGeomAllMask;
 | |
|     sizes.num_properties = wireGeom.num_properties;
 | |
|     sizes.num_colors = wireGeom.num_colors;
 | |
|     sizes.num_shapes = wireGeom.num_shapes;
 | |
|     sizes.num_sections = wireGeom.num_sections;
 | |
|     sizes.num_doodads = wireGeom.num_doodads;
 | |
|     sizes.num_key_aliases = wireGeom.num_key_aliases;
 | |
|     if (XkbAllocGeometry(xkb, &sizes) != Success) {
 | |
|         _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeometry", 0);
 | |
|         return nRead;
 | |
|     }
 | |
|     geom = xkb->geom;
 | |
|     geom->name = XkbInternAtom(buf, FALSE);
 | |
|     geom->width_mm = wireGeom.width_mm;
 | |
|     geom->height_mm = wireGeom.height_mm;
 | |
|     nRead += XkmGetCountedString(file, buf, 100);
 | |
|     geom->label_font = Xstrdup(buf);
 | |
|     if (wireGeom.num_properties > 0) {
 | |
|         char val[1024];
 | |
| 
 | |
|         for (i = 0; i < wireGeom.num_properties; i++) {
 | |
|             nRead += XkmGetCountedString(file, buf, 100);
 | |
|             nRead += XkmGetCountedString(file, val, 1024);
 | |
|             if (XkbAddGeomProperty(geom, buf, val) == NULL) {
 | |
|                 _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeometry", 0);
 | |
|                 return nRead;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if (wireGeom.num_colors > 0) {
 | |
|         for (i = 0; i < wireGeom.num_colors; i++) {
 | |
|             nRead += XkmGetCountedString(file, buf, 100);
 | |
|             if (XkbAddGeomColor(geom, buf, i) == NULL) {
 | |
|                 _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeometry", 0);
 | |
|                 return nRead;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     geom->base_color = &geom->colors[wireGeom.base_color_ndx];
 | |
|     geom->label_color = &geom->colors[wireGeom.label_color_ndx];
 | |
|     if (wireGeom.num_shapes > 0) {
 | |
|         XkbShapePtr shape;
 | |
|         xkmShapeDesc shapeWire;
 | |
|         Atom nameAtom;
 | |
| 
 | |
|         for (i = 0; i < wireGeom.num_shapes; i++) {
 | |
|             register int n;
 | |
|             XkbOutlinePtr ol;
 | |
|             xkmOutlineDesc olWire;
 | |
| 
 | |
|             nRead += XkmGetCountedString(file, buf, 100);
 | |
|             nameAtom = XkbInternAtom(buf, FALSE);
 | |
|             tmp = fread(&shapeWire, SIZEOF(xkmShapeDesc), 1, file);
 | |
|             nRead += tmp * SIZEOF(xkmShapeDesc);
 | |
|             shape = XkbAddGeomShape(geom, nameAtom, shapeWire.num_outlines);
 | |
|             if (!shape) {
 | |
|                 _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeometry", 0);
 | |
|                 return nRead;
 | |
|             }
 | |
|             for (n = 0; n < shapeWire.num_outlines; n++) {
 | |
|                 register int p;
 | |
|                 xkmPointDesc ptWire;
 | |
| 
 | |
|                 tmp = fread(&olWire, SIZEOF(xkmOutlineDesc), 1, file);
 | |
|                 nRead += tmp * SIZEOF(xkmOutlineDesc);
 | |
|                 ol = XkbAddGeomOutline(shape, olWire.num_points);
 | |
|                 if (!ol) {
 | |
|                     _XkbLibError(_XkbErrBadAlloc, "ReadXkmGeometry", 0);
 | |
|                     return nRead;
 | |
|                 }
 | |
|                 ol->num_points = olWire.num_points;
 | |
|                 ol->corner_radius = olWire.corner_radius;
 | |
|                 for (p = 0; p < olWire.num_points; p++) {
 | |
|                     tmp = fread(&ptWire, SIZEOF(xkmPointDesc), 1, file);
 | |
|                     nRead += tmp * SIZEOF(xkmPointDesc);
 | |
|                     ol->points[p].x = ptWire.x;
 | |
|                     ol->points[p].y = ptWire.y;
 | |
|                     if (ptWire.x < shape->bounds.x1)
 | |
|                         shape->bounds.x1 = ptWire.x;
 | |
|                     if (ptWire.x > shape->bounds.x2)
 | |
|                         shape->bounds.x2 = ptWire.x;
 | |
|                     if (ptWire.y < shape->bounds.y1)
 | |
|                         shape->bounds.y1 = ptWire.y;
 | |
|                     if (ptWire.y > shape->bounds.y2)
 | |
|                         shape->bounds.y2 = ptWire.y;
 | |
|                 }
 | |
|             }
 | |
|             if (shapeWire.primary_ndx != XkbNoShape)
 | |
|                 shape->primary = &shape->outlines[shapeWire.primary_ndx];
 | |
|             if (shapeWire.approx_ndx != XkbNoShape)
 | |
|                 shape->approx = &shape->outlines[shapeWire.approx_ndx];
 | |
|         }
 | |
|     }
 | |
|     if (wireGeom.num_sections > 0) {
 | |
|         for (i = 0; i < wireGeom.num_sections; i++) {
 | |
|             tmp = ReadXkmGeomSection(file, geom);
 | |
|             nRead += tmp;
 | |
|             if (tmp == 0)
 | |
|                 return nRead;
 | |
|         }
 | |
|     }
 | |
|     if (wireGeom.num_doodads > 0) {
 | |
|         for (i = 0; i < wireGeom.num_doodads; i++) {
 | |
|             tmp = ReadXkmGeomDoodad(file, geom, NULL);
 | |
|             nRead += tmp;
 | |
|             if (tmp == 0)
 | |
|                 return nRead;
 | |
|         }
 | |
|     }
 | |
|     if ((wireGeom.num_key_aliases > 0) && (geom->key_aliases)) {
 | |
|         int sz = XkbKeyNameLength * 2;
 | |
|         int num = wireGeom.num_key_aliases;
 | |
| 
 | |
|         if (fread(geom->key_aliases, sz, num, file) != num) {
 | |
|             _XkbLibError(_XkbErrBadLength, "ReadXkmGeometry", 0);
 | |
|             return -1;
 | |
|         }
 | |
|         nRead += (num * sz);
 | |
|         geom->num_key_aliases = num;
 | |
|     }
 | |
|     return nRead;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| XkmReadTOC(FILE * file, xkmFileInfo * file_info, int max_toc,
 | |
|            xkmSectionInfo * toc)
 | |
| {
 | |
|     unsigned hdr, tmp;
 | |
|     int nRead = 0;
 | |
|     unsigned i, size_toc;
 | |
| 
 | |
|     hdr = (('x' << 24) | ('k' << 16) | ('m' << 8) | XkmFileVersion);
 | |
|     tmp = XkmGetCARD32(file, &nRead);
 | |
|     if (tmp != hdr) {
 | |
|         if ((tmp & (~0xff)) == (hdr & (~0xff))) {
 | |
|             _XkbLibError(_XkbErrBadFileVersion, "XkmReadTOC", tmp & 0xff);
 | |
|         }
 | |
|         else {
 | |
|             _XkbLibError(_XkbErrBadFileType, "XkmReadTOC", tmp);
 | |
|         }
 | |
|         return 0;
 | |
|     }
 | |
|     if (fread(file_info, SIZEOF(xkmFileInfo), 1, file) != 1)
 | |
|         return 0;
 | |
|     size_toc = file_info->num_toc;
 | |
|     if (size_toc > max_toc) {
 | |
|         DebugF("Warning! Too many TOC entries; last %d ignored\n",
 | |
|                size_toc - max_toc);
 | |
|         size_toc = max_toc;
 | |
|     }
 | |
|     for (i = 0; i < size_toc; i++) {
 | |
|         if (fread(&toc[i], SIZEOF(xkmSectionInfo), 1, file) != 1)
 | |
|             return 0;
 | |
|     }
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| #define	MAX_TOC	16
 | |
| unsigned
 | |
| XkmReadFile(FILE * file, unsigned need, unsigned want, XkbDescPtr *xkb)
 | |
| {
 | |
|     register unsigned i;
 | |
|     xkmSectionInfo toc[MAX_TOC] = { 0 }, tmpTOC = { 0 };
 | |
|     xkmFileInfo fileInfo;
 | |
|     unsigned tmp, nRead = 0;
 | |
|     unsigned which = need | want;
 | |
| 
 | |
|     if (!XkmReadTOC(file, &fileInfo, MAX_TOC, toc))
 | |
|         return which;
 | |
|     if ((fileInfo.present & need) != need) {
 | |
|         _XkbLibError(_XkbErrIllegalContents, "XkmReadFile",
 | |
|                      need & (~fileInfo.present));
 | |
|         return which;
 | |
|     }
 | |
|     if (*xkb == NULL)
 | |
|         *xkb = XkbAllocKeyboard();
 | |
|     for (i = 0; i < fileInfo.num_toc; i++) {
 | |
|         fseek(file, toc[i].offset, SEEK_SET);
 | |
|         tmp = fread(&tmpTOC, SIZEOF(xkmSectionInfo), 1, file);
 | |
|         nRead = tmp * SIZEOF(xkmSectionInfo);
 | |
|         if ((tmpTOC.type != toc[i].type) || (tmpTOC.format != toc[i].format) ||
 | |
|             (tmpTOC.size != toc[i].size) || (tmpTOC.offset != toc[i].offset)) {
 | |
|             return which;
 | |
|         }
 | |
|         if ((which & (1 << tmpTOC.type)) == 0) {
 | |
|             continue;
 | |
|         }
 | |
|         switch (tmpTOC.type) {
 | |
|         case XkmVirtualModsIndex:
 | |
|             tmp = ReadXkmVirtualMods(file, *xkb, NULL);
 | |
|             break;
 | |
|         case XkmTypesIndex:
 | |
|             tmp = ReadXkmKeyTypes(file, *xkb, NULL);
 | |
|             break;
 | |
|         case XkmCompatMapIndex:
 | |
|             tmp = ReadXkmCompatMap(file, *xkb, NULL);
 | |
|             break;
 | |
|         case XkmKeyNamesIndex:
 | |
|             tmp = ReadXkmKeycodes(file, *xkb, NULL);
 | |
|             break;
 | |
|         case XkmIndicatorsIndex:
 | |
|             tmp = ReadXkmIndicators(file, *xkb, NULL);
 | |
|             break;
 | |
|         case XkmSymbolsIndex:
 | |
|             tmp = ReadXkmSymbols(file, *xkb);
 | |
|             break;
 | |
|         case XkmGeometryIndex:
 | |
|             tmp = ReadXkmGeometry(file, *xkb);
 | |
|             break;
 | |
|         default:
 | |
|             _XkbLibError(_XkbErrBadImplementation,
 | |
|                          XkbConfigText(tmpTOC.type, XkbMessage), 0);
 | |
|             tmp = 0;
 | |
|             break;
 | |
|         }
 | |
|         if (tmp > 0) {
 | |
|             nRead += tmp;
 | |
|             which &= ~(1 << toc[i].type);
 | |
|             (*xkb)->defined |= (1 << toc[i].type);
 | |
|         }
 | |
|         if (nRead != tmpTOC.size) {
 | |
|             _XkbLibError(_XkbErrBadLength,
 | |
|                          XkbConfigText(tmpTOC.type, XkbMessage),
 | |
|                          nRead - tmpTOC.size);
 | |
|         }
 | |
|     }
 | |
|     return which;
 | |
| }
 |