/************************************************************ 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. ********************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "XKMformat.h" #include "XKBfileInt.h" typedef struct _XkmInfo { unsigned short bound_vmods; unsigned short named_vmods; unsigned char num_bound; unsigned char group_compat; unsigned short num_group_compat; unsigned short num_leds; int total_vmodmaps; } XkmInfo; /***====================================================================***/ #define xkmPutCARD8(f,v) (putc(v,f),1) static int xkmPutCARD16(FILE *file, unsigned val) { CARD16 tmp = val; fwrite(&tmp, 2, 1, file); return 2; } static int xkmPutCARD32(FILE *file, unsigned long val) { CARD32 tmp = val; fwrite(&tmp, 4, 1, file); return 4; } static int xkmPutPadding(FILE *file, unsigned pad) { int i; for (i = 0; i < pad; i++) { putc('\0', file); } return pad; } static int xkmPutCountedBytes(FILE *file, char *ptr, unsigned count) { register int nOut; register unsigned pad; if (count == 0) return xkmPutCARD32(file, (unsigned long) 0); xkmPutCARD16(file, count); nOut = fwrite(ptr, 1, count, file); if (nOut < 0) return 2; nOut = count + 2; pad = XkbPaddedSize(nOut) - nOut; if (pad) xkmPutPadding(file, pad); return nOut + pad; } static unsigned xkmSizeCountedString(char *str) { if (str == NULL) return 4; return XkbPaddedSize(strlen(str) + 2); } static int xkmPutCountedString(FILE *file, char *str) { if (str == NULL) return xkmPutCARD32(file, (unsigned long) 0); return xkmPutCountedBytes(file, str, strlen(str)); } #define xkmSizeCountedAtomString(d,a) \ xkmSizeCountedString(XkbAtomGetString((d),(a))) #define xkmPutCountedAtomString(d,f,a) \ xkmPutCountedString((f),XkbAtomGetString((d),(a))) /***====================================================================***/ static unsigned SizeXKMVirtualMods(XkbFileInfo *result, XkmInfo *info, xkmSectionInfo *toc, int *offset_inout) { Display *dpy; XkbDescPtr xkb; unsigned nBound, bound; unsigned nNamed, named, szNames; register unsigned i, bit; xkb = result->xkb; if ((!xkb) || (!xkb->names) || (!xkb->server)) { _XkbLibError(_XkbErrMissingVMods, "SizeXKMVirtualMods", 0); return 0; } dpy = xkb->dpy; bound = named = 0; for (i = nBound = nNamed = szNames = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) { if (xkb->server->vmods[i] != XkbNoModifierMask) { bound |= bit; nBound++; } if (xkb->names->vmods[i] != None) { named |= bit; szNames += xkmSizeCountedAtomString(dpy, xkb->names->vmods[i]); nNamed++; } } info->num_bound = nBound; info->bound_vmods = bound; info->named_vmods = named; if ((nBound == 0) && (nNamed == 0)) return 0; toc->type = XkmVirtualModsIndex; toc->format = MSBFirst; toc->size = 4 + XkbPaddedSize(nBound) + szNames + SIZEOF(xkmSectionInfo); toc->offset = *offset_inout; (*offset_inout) += toc->size; return 1; } static unsigned WriteXKMVirtualMods(FILE *file, XkbFileInfo *result, XkmInfo *info) { register unsigned int i, bit; XkbDescPtr xkb; Display *dpy; unsigned size = 0; xkb = result->xkb; dpy = xkb->dpy; size += xkmPutCARD16(file, info->bound_vmods); size += xkmPutCARD16(file, info->named_vmods); for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) { if (info->bound_vmods & bit) size += xkmPutCARD8(file, xkb->server->vmods[i]); } if ((i = XkbPaddedSize(info->num_bound) - info->num_bound) > 0) size += xkmPutPadding(file, i); for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) { if (info->named_vmods & bit) { register char *name; name = XkbAtomGetString(dpy, xkb->names->vmods[i]); size += xkmPutCountedString(file, name); } } return size; } /***====================================================================***/ static unsigned SizeXKMKeycodes(XkbFileInfo *result, xkmSectionInfo *toc, int *offset_inout) { XkbDescPtr xkb; Atom kcName; int size = 0; Display *dpy; xkb = result->xkb; if ((!xkb) || (!xkb->names) || (!xkb->names->keys)) { _XkbLibError(_XkbErrMissingNames, "SizeXKMKeycodes", 0); return 0; } dpy = xkb->dpy; kcName = xkb->names->keycodes; size += 4; /* min and max keycode */ size += xkmSizeCountedAtomString(dpy, kcName); size += XkbNumKeys(xkb) * sizeof(XkbKeyNameRec); if (xkb->names->num_key_aliases > 0) { if (xkb->names->key_aliases != NULL) size += xkb->names->num_key_aliases * sizeof(XkbKeyAliasRec); else xkb->names->num_key_aliases = 0; } toc->type = XkmKeyNamesIndex; toc->format = MSBFirst; toc->size = size + SIZEOF(xkmSectionInfo); toc->offset = (*offset_inout); (*offset_inout) += toc->size; return 1; } static unsigned WriteXKMKeycodes(FILE *file, XkbFileInfo *result) { XkbDescPtr xkb; Atom kcName; char *start; Display *dpy; unsigned tmp, size = 0; xkb = result->xkb; dpy = xkb->dpy; kcName = xkb->names->keycodes; start = xkb->names->keys[xkb->min_key_code].name; size += xkmPutCountedString(file, XkbAtomGetString(dpy, kcName)); size += xkmPutCARD8(file, xkb->min_key_code); size += xkmPutCARD8(file, xkb->max_key_code); size += xkmPutCARD8(file, xkb->names->num_key_aliases); size += xkmPutPadding(file, 1); tmp = fwrite(start, sizeof(XkbKeyNameRec), XkbNumKeys(xkb), file); size += tmp * sizeof(XkbKeyNameRec); if (xkb->names->num_key_aliases > 0) { tmp = fwrite((char *) xkb->names->key_aliases, sizeof(XkbKeyAliasRec), xkb->names->num_key_aliases, file); size += tmp * sizeof(XkbKeyAliasRec); } return size; } /***====================================================================***/ static unsigned SizeXKMKeyTypes(XkbFileInfo *result, xkmSectionInfo *toc, int *offset_inout) { register unsigned i, n, size; XkbKeyTypePtr type; XkbDescPtr xkb; Display *dpy; char *name; xkb = result->xkb; if ((!xkb) || (!xkb->map) || (!xkb->map->types)) { _XkbLibError(_XkbErrMissingTypes, "SizeXKBKeyTypes", 0); return 0; } dpy = xkb->dpy; if (xkb->map->num_types < XkbNumRequiredTypes) { _XkbLibError(_XkbErrMissingReqTypes, "SizeXKBKeyTypes", 0); return 0; } if (xkb->names) name = XkbAtomGetString(dpy, xkb->names->types); else name = NULL; size = xkmSizeCountedString(name); size += 4; /* room for # of key types + padding */ for (i = 0, type = xkb->map->types; i < xkb->map->num_types; i++, type++) { size += SIZEOF(xkmKeyTypeDesc); size += SIZEOF(xkmKTMapEntryDesc) * type->map_count; size += xkmSizeCountedAtomString(dpy, type->name); if (type->preserve) size += SIZEOF(xkmModsDesc) * type->map_count; if (type->level_names) { Atom *names; names = type->level_names; for (n = 0; n < (unsigned) type->num_levels; n++) { size += xkmSizeCountedAtomString(dpy, names[n]); } } } toc->type = XkmTypesIndex; toc->format = MSBFirst; toc->size = size + SIZEOF(xkmSectionInfo); toc->offset = (*offset_inout); (*offset_inout) += toc->size; return 1; } static unsigned WriteXKMKeyTypes(FILE *file, XkbFileInfo *result) { register unsigned i, n; XkbDescPtr xkb; XkbKeyTypePtr type; xkmKeyTypeDesc wire; XkbKTMapEntryPtr entry; xkmKTMapEntryDesc wire_entry; Atom *names; Display *dpy; unsigned tmp, size = 0; char *name; xkb = result->xkb; dpy = xkb->dpy; if (xkb->names) name = XkbAtomGetString(dpy, xkb->names->types); else name = NULL; size += xkmPutCountedString(file, name); size += xkmPutCARD16(file, xkb->map->num_types); size += xkmPutPadding(file, 2); type = xkb->map->types; for (i = 0; i < xkb->map->num_types; i++, type++) { wire.realMods = type->mods.real_mods; wire.virtualMods = type->mods.vmods; wire.numLevels = type->num_levels; wire.nMapEntries = type->map_count; wire.preserve = (type->preserve != NULL); if (type->level_names != NULL) wire.nLevelNames = type->num_levels; else wire.nLevelNames = 0; tmp = fwrite(&wire, SIZEOF(xkmKeyTypeDesc), 1, file); size += tmp * SIZEOF(xkmKeyTypeDesc); for (n = 0, entry = type->map; n < type->map_count; n++, entry++) { wire_entry.level = entry->level; wire_entry.realMods = entry->mods.real_mods; wire_entry.virtualMods = entry->mods.vmods; tmp = fwrite(&wire_entry, SIZEOF(xkmKTMapEntryDesc), 1, file); size += tmp * SIZEOF(xkmKTMapEntryDesc); } size += xkmPutCountedString(file, XkbAtomGetString(dpy, type->name)); if (type->preserve) { xkmModsDesc p_entry; XkbModsPtr pre; for (n = 0, pre = type->preserve; n < type->map_count; n++, pre++) { p_entry.realMods = pre->real_mods; p_entry.virtualMods = pre->vmods; tmp = fwrite(&p_entry, SIZEOF(xkmModsDesc), 1, file); size += tmp * SIZEOF(xkmModsDesc); } } if (type->level_names != NULL) { names = type->level_names; for (n = 0; n < wire.nLevelNames; n++) { size += xkmPutCountedString(file, XkbAtomGetString(dpy, names[n])); } } } return size; } /***====================================================================***/ static unsigned SizeXKMCompatMap(XkbFileInfo *result, XkmInfo *info, xkmSectionInfo *toc, int *offset_inout) { XkbDescPtr xkb; char *name; int size; register int i; unsigned groups, nGroups; Display *dpy; xkb = result->xkb; if ((!xkb) || (!xkb->compat) || (!xkb->compat->sym_interpret)) { _XkbLibError(_XkbErrMissingCompatMap, "SizeXKMCompatMap", 0); return 0; } dpy = xkb->dpy; if (xkb->names) name = XkbAtomGetString(dpy, xkb->names->compat); else name = NULL; for (i = groups = nGroups = 0; i < XkbNumKbdGroups; i++) { if ((xkb->compat->groups[i].real_mods != 0) || (xkb->compat->groups[i].vmods != 0)) { groups |= (1 << i); nGroups++; } } info->group_compat = groups; info->num_group_compat = nGroups; size = 4; /* room for num_si and group_compat mask */ size += xkmSizeCountedString(name); size += (SIZEOF(xkmSymInterpretDesc) * xkb->compat->num_si); size += (SIZEOF(xkmModsDesc) * nGroups); toc->type = XkmCompatMapIndex; toc->format = MSBFirst; toc->size = size + SIZEOF(xkmSectionInfo); toc->offset = (*offset_inout); (*offset_inout) += toc->size; return 1; } static unsigned WriteXKMCompatMap(FILE *file, XkbFileInfo *result, XkmInfo *info) { register unsigned i; char *name; XkbDescPtr xkb; XkbSymInterpretPtr interp; xkmSymInterpretDesc wire; Display *dpy; unsigned tmp, size = 0; xkb = result->xkb; dpy = xkb->dpy; if (xkb->names) name = XkbAtomGetString(dpy, xkb->names->compat); else name = NULL; size += xkmPutCountedString(file, name); size += xkmPutCARD16(file, xkb->compat->num_si); size += xkmPutCARD8(file, info->group_compat); size += xkmPutPadding(file, 1); interp = xkb->compat->sym_interpret; for (i = 0; i < xkb->compat->num_si; i++, interp++) { wire.sym = interp->sym; wire.mods = interp->mods; wire.match = interp->match; wire.virtualMod = interp->virtual_mod; wire.flags = interp->flags; wire.actionType = interp->act.type; wire.actionData[0] = interp->act.data[0]; wire.actionData[1] = interp->act.data[1]; wire.actionData[2] = interp->act.data[2]; wire.actionData[3] = interp->act.data[3]; wire.actionData[4] = interp->act.data[4]; wire.actionData[5] = interp->act.data[5]; wire.actionData[6] = interp->act.data[6]; tmp = fwrite(&wire, SIZEOF(xkmSymInterpretDesc), 1, file); size += tmp * SIZEOF(xkmSymInterpretDesc); } if (info->group_compat) { register unsigned bit; xkmModsDesc modsWire; for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) { if (info->group_compat & bit) { modsWire.realMods = xkb->compat->groups[i].real_mods; modsWire.virtualMods = xkb->compat->groups[i].vmods; fwrite(&modsWire, SIZEOF(xkmModsDesc), 1, file); size += SIZEOF(xkmModsDesc); } } } return size; } /***====================================================================***/ static unsigned SizeXKMSymbols(XkbFileInfo *result, XkmInfo *info, xkmSectionInfo *toc, int *offset_inout) { Display *dpy; XkbDescPtr xkb; unsigned size; register int i, nSyms; char *name; xkb = result->xkb; if ((!xkb) || (!xkb->map) || ((!xkb->map->syms))) { _XkbLibError(_XkbErrMissingSymbols, "SizeXKMSymbols", 0); return 0; } dpy = xkb->dpy; if (xkb->names && (xkb->names->symbols != None)) name = XkbAtomGetString(dpy, xkb->names->symbols); else name = NULL; size = xkmSizeCountedString(name); size += 4; /* min and max keycode, group names mask */ for (i = 0; i < XkbNumKbdGroups; i++) { if (xkb->names->groups[i] != None) size += xkmSizeCountedAtomString(dpy, xkb->names->groups[i]); } info->total_vmodmaps = 0; for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) { nSyms = XkbKeyNumSyms(xkb, i); size += SIZEOF(xkmKeySymMapDesc) + (nSyms * 4); if (xkb->server) { if (xkb->server->explicit[i] & XkbExplicitKeyTypesMask) { register int g; for (g = XkbKeyNumGroups(xkb, i) - 1; g >= 0; g--) { if (xkb->server->explicit[i] & (1 << g)) { XkbKeyTypePtr type; char *name; type = XkbKeyKeyType(xkb, i, g); name = XkbAtomGetString(dpy, type->name); if (name != NULL) size += xkmSizeCountedString(name); } } } if (XkbKeyHasActions(xkb, i)) size += nSyms * SIZEOF(xkmActionDesc); if (xkb->server->behaviors[i].type != XkbKB_Default) size += SIZEOF(xkmBehaviorDesc); if (xkb->server->vmodmap && (xkb->server->vmodmap[i] != 0)) info->total_vmodmaps++; } } size += info->total_vmodmaps * SIZEOF(xkmVModMapDesc); toc->type = XkmSymbolsIndex; toc->format = MSBFirst; toc->size = size + SIZEOF(xkmSectionInfo); toc->offset = (*offset_inout); (*offset_inout) += toc->size; return 1; } static unsigned WriteXKMSymbols(FILE *file, XkbFileInfo *result, XkmInfo *info) { Display *dpy; XkbDescPtr xkb; register int i, n; xkmKeySymMapDesc wireMap; char *name; unsigned tmp, size = 0; xkb = result->xkb; dpy = xkb->dpy; if (xkb->names && (xkb->names->symbols != None)) name = XkbAtomGetString(dpy, xkb->names->symbols); else name = NULL; size += xkmPutCountedString(file, name); for (tmp = i = 0; i < XkbNumKbdGroups; i++) { if (xkb->names->groups[i] != None) tmp |= (1 << i); } size += xkmPutCARD8(file, xkb->min_key_code); size += xkmPutCARD8(file, xkb->max_key_code); size += xkmPutCARD8(file, tmp); size += xkmPutCARD8(file, info->total_vmodmaps); for (i = 0, n = 1; i < XkbNumKbdGroups; i++, n <<= 1) { if ((tmp & n) == 0) continue; size += xkmPutCountedAtomString(dpy, file, xkb->names->groups[i]); } for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) { char *typeName[XkbNumKbdGroups]; wireMap.width = XkbKeyGroupsWidth(xkb, i); wireMap.num_groups = XkbKeyGroupInfo(xkb, i); if (xkb->map && xkb->map->modmap) wireMap.modifier_map = xkb->map->modmap[i]; else wireMap.modifier_map = 0; wireMap.flags = 0; bzero((char *) typeName, XkbNumKbdGroups * sizeof(char *)); if (xkb->server) { if (xkb->server->explicit[i] & XkbExplicitKeyTypesMask) { register int g; for (g = 0; g < XkbKeyNumGroups(xkb, i); g++) { if (xkb->server->explicit[i] & (1 << g)) { XkbKeyTypePtr type; type = XkbKeyKeyType(xkb, i, g); typeName[g] = XkbAtomGetString(dpy, type->name); if (typeName[g] != NULL) wireMap.flags |= (1 << g); } } } if (XkbKeyHasActions(xkb, i)) wireMap.flags |= XkmKeyHasActions; if (xkb->server->behaviors[i].type != XkbKB_Default) wireMap.flags |= XkmKeyHasBehavior; if ((xkb->server->explicit[i] & XkbExplicitAutoRepeatMask) && (xkb->ctrls != NULL)) { if (xkb->ctrls->per_key_repeat[(i / 8)] & (1 << (i % 8))) wireMap.flags |= XkmRepeatingKey; else wireMap.flags |= XkmNonRepeatingKey; } } tmp = fwrite(&wireMap, SIZEOF(xkmKeySymMapDesc), 1, file); size += tmp * SIZEOF(xkmKeySymMapDesc); if (xkb->server->explicit[i] & XkbExplicitKeyTypesMask) { register int g; for (g = 0; g < XkbNumKbdGroups; g++) { if (typeName[g] != NULL) size += xkmPutCountedString(file, typeName[g]); } } if (XkbNumGroups(wireMap.num_groups) > 0) { KeySym *sym; sym = XkbKeySymsPtr(xkb, i); for (n = XkbKeyNumSyms(xkb, i); n > 0; n--, sym++) { size += xkmPutCARD32(file, (CARD32) *sym); } if (wireMap.flags & XkmKeyHasActions) { XkbAction *act; act = XkbKeyActionsPtr(xkb, i); for (n = XkbKeyNumActions(xkb, i); n > 0; n--, act++) { tmp = fwrite(act, SIZEOF(xkmActionDesc), 1, file); size += tmp * SIZEOF(xkmActionDesc); } } } if (wireMap.flags & XkmKeyHasBehavior) { xkmBehaviorDesc b; b.type = xkb->server->behaviors[i].type; b.data = xkb->server->behaviors[i].data; tmp = fwrite(&b, SIZEOF(xkmBehaviorDesc), 1, file); size += tmp * SIZEOF(xkmBehaviorDesc); } } if (info->total_vmodmaps > 0) { xkmVModMapDesc v; for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) { if (xkb->server->vmodmap[i] != 0) { v.key = i; v.vmods = xkb->server->vmodmap[i]; tmp = fwrite(&v, SIZEOF(xkmVModMapDesc), 1, file); size += tmp * SIZEOF(xkmVModMapDesc); } } } return size; } /***====================================================================***/ static unsigned SizeXKMIndicators(XkbFileInfo *result, XkmInfo *info, xkmSectionInfo *toc, int *offset_inout) { Display *dpy; XkbDescPtr xkb; unsigned size; register unsigned i, nLEDs; xkb = result->xkb; if ((xkb == NULL) || (xkb->indicators == NULL)) { /* _XkbLibError(_XkbErrMissingIndicators,"SizeXKMIndicators",0);*/ return 0; } dpy = xkb->dpy; nLEDs = 0; size = 8; /* number of indicator maps/physical indicators */ if (xkb->indicators != NULL) { for (i = 0; i < XkbNumIndicators; i++) { XkbIndicatorMapPtr map = &xkb->indicators->maps[i]; if ((map->flags != 0) || (map->which_groups != 0) || (map->groups != 0) || (map->which_mods != 0) || (map->mods.real_mods != 0) || (map->mods.vmods != 0) || (map->ctrls != 0) || (xkb->names && (xkb->names->indicators[i] != None))) { char *name; if (xkb->names && xkb->names->indicators[i] != None) { name = XkbAtomGetString(dpy, xkb->names->indicators[i]); } else name = NULL; size += xkmSizeCountedString(name); size += SIZEOF(xkmIndicatorMapDesc); nLEDs++; } } } info->num_leds = nLEDs; toc->type = XkmIndicatorsIndex; toc->format = MSBFirst; toc->size = size + SIZEOF(xkmSectionInfo); toc->offset = (*offset_inout); (*offset_inout) += toc->size; return 1; } static unsigned WriteXKMIndicators(FILE *file, XkbFileInfo *result, XkmInfo *info) { Display *dpy; XkbDescPtr xkb; register unsigned i; xkmIndicatorMapDesc wire; unsigned tmp, size = 0; xkb = result->xkb; dpy = xkb->dpy; size += xkmPutCARD8(file, info->num_leds); size += xkmPutPadding(file, 3); size += xkmPutCARD32(file, xkb->indicators->phys_indicators); if (xkb->indicators != NULL) { for (i = 0; i < XkbNumIndicators; i++) { XkbIndicatorMapPtr map = &xkb->indicators->maps[i]; if ((map->flags != 0) || (map->which_groups != 0) || (map->groups != 0) || (map->which_mods != 0) || (map->mods.real_mods != 0) || (map->mods.vmods != 0) || (map->ctrls != 0) || (xkb->names && (xkb->names->indicators[i] != None))) { char *name; if (xkb->names && xkb->names->indicators[i] != None) { name = XkbAtomGetString(dpy, xkb->names->indicators[i]); } else name = NULL; size += xkmPutCountedString(file, name); wire.indicator = i + 1; wire.flags = map->flags; wire.which_mods = map->which_mods; wire.real_mods = map->mods.real_mods; wire.vmods = map->mods.vmods; wire.which_groups = map->which_groups; wire.groups = map->groups; wire.ctrls = map->ctrls; tmp = fwrite(&wire, SIZEOF(xkmIndicatorMapDesc), 1, file); size += tmp * SIZEOF(xkmIndicatorMapDesc); } } } return size; } /***====================================================================***/ static unsigned SizeXKMGeomDoodad(XkbFileInfo *result, XkbDoodadPtr doodad) { unsigned size; size = SIZEOF(xkmAnyDoodadDesc); size += xkmSizeCountedAtomString(result->xkb->dpy, doodad->any.name); if (doodad->any.type == XkbTextDoodad) { size += xkmSizeCountedString(doodad->text.text); size += xkmSizeCountedString(doodad->text.font); } else if (doodad->any.type == XkbLogoDoodad) { size += xkmSizeCountedString(doodad->logo.logo_name); } return size; } static unsigned SizeXKMGeomSection(XkbFileInfo *result, XkbSectionPtr section) { register int i; unsigned size; size = SIZEOF(xkmSectionDesc); size += xkmSizeCountedAtomString(result->xkb->dpy, section->name); if (section->rows) { XkbRowPtr row; for (row = section->rows, i = 0; i < section->num_rows; i++, row++) { size += SIZEOF(xkmRowDesc); size += row->num_keys * SIZEOF(xkmKeyDesc); } } if (section->doodads) { XkbDoodadPtr doodad; for (doodad = section->doodads, i = 0; i < section->num_doodads; i++, doodad++) { size += SizeXKMGeomDoodad(result, doodad); } } if (section->overlays) { XkbOverlayPtr ol; for (ol = section->overlays, i = 0; i < section->num_overlays; i++, ol++) { register int r; XkbOverlayRowPtr row; size += xkmSizeCountedAtomString(result->xkb->dpy, ol->name); size += SIZEOF(xkmOverlayDesc); for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) { size += SIZEOF(xkmOverlayRowDesc); size += row->num_keys * SIZEOF(xkmOverlayKeyDesc); } } } return size; } static unsigned SizeXKMGeometry(XkbFileInfo *result, xkmSectionInfo *toc, int *offset_inout) { register int i; Display *dpy; XkbDescPtr xkb; XkbGeometryPtr geom; unsigned size; xkb = result->xkb; if ((!xkb) || (!xkb->geom)) return 0; dpy = xkb->dpy; geom = xkb->geom; size = xkmSizeCountedAtomString(dpy, geom->name); size += SIZEOF(xkmGeometryDesc); size += xkmSizeCountedString(geom->label_font); if (geom->properties) { XkbPropertyPtr prop; for (i = 0, prop = geom->properties; i < geom->num_properties; i++, prop++) { size += xkmSizeCountedString(prop->name); size += xkmSizeCountedString(prop->value); } } if (geom->colors) { XkbColorPtr color; for (i = 0, color = geom->colors; i < geom->num_colors; i++, color++) { size += xkmSizeCountedString(color->spec); } } if (geom->shapes) { XkbShapePtr shape; for (i = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) { register int n; register XkbOutlinePtr ol; size += xkmSizeCountedAtomString(dpy, shape->name); size += SIZEOF(xkmShapeDesc); for (n = 0, ol = shape->outlines; n < shape->num_outlines; n++, ol++) { size += SIZEOF(xkmOutlineDesc); size += ol->num_points * SIZEOF(xkmPointDesc); } } } if (geom->sections) { XkbSectionPtr section; for (i = 0, section = geom->sections; i < geom->num_sections; i++, section++) { size += SizeXKMGeomSection(result, section); } } if (geom->doodads) { XkbDoodadPtr doodad; for (i = 0, doodad = geom->doodads; i < geom->num_doodads; i++, doodad++) { size += SizeXKMGeomDoodad(result, doodad); } } if (geom->key_aliases) { size += geom->num_key_aliases * (XkbKeyNameLength * 2); } toc->type = XkmGeometryIndex; toc->format = MSBFirst; toc->size = size + SIZEOF(xkmSectionInfo); toc->offset = (*offset_inout); (*offset_inout) += toc->size; return 1; } static unsigned WriteXKMGeomDoodad(FILE *file, XkbFileInfo *result, XkbDoodadPtr doodad) { Display *dpy; XkbDescPtr xkb; xkmDoodadDesc doodadWire; unsigned tmp, size = 0; xkb = result->xkb; dpy = xkb->dpy; bzero((char *) &doodadWire, sizeof(doodadWire)); doodadWire.any.type = doodad->any.type; doodadWire.any.priority = doodad->any.priority; doodadWire.any.top = doodad->any.top; doodadWire.any.left = doodad->any.left; switch (doodad->any.type) { case XkbOutlineDoodad: case XkbSolidDoodad: doodadWire.shape.angle = doodad->shape.angle; doodadWire.shape.color_ndx = doodad->shape.color_ndx; doodadWire.shape.shape_ndx = doodad->shape.shape_ndx; break; case XkbTextDoodad: doodadWire.text.angle = doodad->text.angle; doodadWire.text.width = doodad->text.width; doodadWire.text.height = doodad->text.height; doodadWire.text.color_ndx = doodad->text.color_ndx; break; case XkbIndicatorDoodad: doodadWire.indicator.shape_ndx = doodad->indicator.shape_ndx; doodadWire.indicator.on_color_ndx = doodad->indicator.on_color_ndx; doodadWire.indicator.off_color_ndx = doodad->indicator.off_color_ndx; break; case XkbLogoDoodad: doodadWire.logo.angle = doodad->logo.angle; doodadWire.logo.color_ndx = doodad->logo.color_ndx; doodadWire.logo.shape_ndx = doodad->logo.shape_ndx; break; default: _XkbLibError(_XkbErrIllegalDoodad, "WriteXKMGeomDoodad", doodad->any.type); return 0; } size += xkmPutCountedAtomString(dpy, file, doodad->any.name); tmp = fwrite(&doodadWire, SIZEOF(xkmDoodadDesc), 1, file); size += tmp * SIZEOF(xkmDoodadDesc); if (doodad->any.type == XkbTextDoodad) { size += xkmPutCountedString(file, doodad->text.text); size += xkmPutCountedString(file, doodad->text.font); } else if (doodad->any.type == XkbLogoDoodad) { size += xkmPutCountedString(file, doodad->logo.logo_name); } return size; } static unsigned WriteXKMGeomOverlay(FILE *file, XkbFileInfo *result, XkbOverlayPtr ol) { register int r, k; Display *dpy; XkbDescPtr xkb; XkbOverlayRowPtr row; xkmOverlayDesc olWire; xkmOverlayRowDesc rowWire; xkmOverlayKeyDesc keyWire; unsigned tmp, size = 0; xkb = result->xkb; dpy = xkb->dpy; bzero((char *) &olWire, sizeof(olWire)); bzero((char *) &rowWire, sizeof(rowWire)); bzero((char *) &keyWire, sizeof(keyWire)); size += xkmPutCountedAtomString(dpy, file, ol->name); olWire.num_rows = ol->num_rows; tmp = fwrite(&olWire, SIZEOF(xkmOverlayDesc), 1, file); size += tmp * SIZEOF(xkmOverlayDesc); for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) { XkbOverlayKeyPtr key; rowWire.row_under = row->row_under; rowWire.num_keys = row->num_keys; tmp = fwrite(&rowWire, SIZEOF(xkmOverlayRowDesc), 1, file); size += tmp * SIZEOF(xkmOverlayRowDesc); for (k = 0, key = row->keys; k < row->num_keys; k++, key++) { memcpy(keyWire.over, key->over.name, XkbKeyNameLength); memcpy(keyWire.under, key->under.name, XkbKeyNameLength); tmp = fwrite(&keyWire, SIZEOF(xkmOverlayKeyDesc), 1, file); size += tmp * SIZEOF(xkmOverlayKeyDesc); } } return size; } static unsigned WriteXKMGeomSection(FILE *file, XkbFileInfo *result, XkbSectionPtr section) { register int i; Display *dpy; XkbDescPtr xkb; xkmSectionDesc sectionWire; unsigned tmp, size = 0; xkb = result->xkb; dpy = xkb->dpy; size += xkmPutCountedAtomString(dpy, file, section->name); sectionWire.top = section->top; sectionWire.left = section->left; sectionWire.width = section->width; sectionWire.height = section->height; sectionWire.angle = section->angle; sectionWire.priority = section->priority; sectionWire.num_rows = section->num_rows; sectionWire.num_doodads = section->num_doodads; sectionWire.num_overlays = section->num_overlays; tmp = fwrite(§ionWire, SIZEOF(xkmSectionDesc), 1, file); size += tmp * SIZEOF(xkmSectionDesc); if (section->rows) { register unsigned k; XkbRowPtr row; xkmRowDesc rowWire; XkbKeyPtr key; xkmKeyDesc keyWire; for (i = 0, row = section->rows; i < section->num_rows; i++, row++) { rowWire.top = row->top; rowWire.left = row->left; rowWire.num_keys = row->num_keys; rowWire.vertical = row->vertical; tmp = fwrite(&rowWire, SIZEOF(xkmRowDesc), 1, file); size += tmp * SIZEOF(xkmRowDesc); for (k = 0, key = row->keys; k < row->num_keys; k++, key++) { memcpy(keyWire.name, key->name.name, XkbKeyNameLength); keyWire.gap = key->gap; keyWire.shape_ndx = key->shape_ndx; keyWire.color_ndx = key->color_ndx; tmp = fwrite(&keyWire, SIZEOF(xkmKeyDesc), 1, file); size += tmp * SIZEOF(xkmKeyDesc); } } } if (section->doodads) { XkbDoodadPtr doodad; for (i = 0, doodad = section->doodads; i < section->num_doodads; i++, doodad++) { size += WriteXKMGeomDoodad(file, result, doodad); } } if (section->overlays) { XkbOverlayPtr ol; for (i = 0, ol = section->overlays; i < section->num_overlays; i++, ol++) { size += WriteXKMGeomOverlay(file, result, ol); } } return size; } static unsigned WriteXKMGeometry(FILE *file, XkbFileInfo *result) { register int i; Display *dpy; XkbDescPtr xkb; XkbGeometryPtr geom; xkmGeometryDesc wire; unsigned tmp, size = 0; xkb = result->xkb; if ((!xkb) || (!xkb->geom)) return 0; dpy = xkb->dpy; geom = xkb->geom; wire.width_mm = geom->width_mm; wire.height_mm = geom->height_mm; wire.base_color_ndx = XkbGeomColorIndex(geom, geom->base_color); wire.label_color_ndx = XkbGeomColorIndex(geom, geom->label_color); wire.num_properties = geom->num_properties; wire.num_colors = geom->num_colors; wire.num_shapes = geom->num_shapes; wire.num_sections = geom->num_sections; wire.num_doodads = geom->num_doodads; wire.num_key_aliases = geom->num_key_aliases; size += xkmPutCountedAtomString(dpy, file, geom->name); tmp = fwrite(&wire, SIZEOF(xkmGeometryDesc), 1, file); size += tmp * SIZEOF(xkmGeometryDesc); size += xkmPutCountedString(file, geom->label_font); if (geom->properties) { XkbPropertyPtr prop; for (i = 0, prop = geom->properties; i < geom->num_properties; i++, prop++) { size += xkmPutCountedString(file, prop->name); size += xkmPutCountedString(file, prop->value); } } if (geom->colors) { XkbColorPtr color; for (i = 0, color = geom->colors; i < geom->num_colors; i++, color++) { size += xkmPutCountedString(file, color->spec); } } if (geom->shapes) { XkbShapePtr shape; xkmShapeDesc shapeWire; for (i = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) { register int n; XkbOutlinePtr ol; xkmOutlineDesc olWire; bzero((char *) &shapeWire, sizeof(xkmShapeDesc)); size += xkmPutCountedAtomString(dpy, file, shape->name); shapeWire.num_outlines = shape->num_outlines; if (shape->primary != NULL) shapeWire.primary_ndx = XkbOutlineIndex(shape, shape->primary); else shapeWire.primary_ndx = XkbNoShape; if (shape->approx != NULL) shapeWire.approx_ndx = XkbOutlineIndex(shape, shape->approx); else shapeWire.approx_ndx = XkbNoShape; tmp = fwrite(&shapeWire, SIZEOF(xkmShapeDesc), 1, file); size += tmp * SIZEOF(xkmShapeDesc); for (n = 0, ol = shape->outlines; n < shape->num_outlines; n++, ol++) { register int p; XkbPointPtr pt; xkmPointDesc ptWire; olWire.num_points = ol->num_points; olWire.corner_radius = ol->corner_radius; tmp = fwrite(&olWire, SIZEOF(xkmOutlineDesc), 1, file); size += tmp * SIZEOF(xkmOutlineDesc); for (p = 0, pt = ol->points; p < ol->num_points; p++, pt++) { ptWire.x = pt->x; ptWire.y = pt->y; tmp = fwrite(&ptWire, SIZEOF(xkmPointDesc), 1, file); size += tmp * SIZEOF(xkmPointDesc); } } } } if (geom->sections) { XkbSectionPtr section; for (i = 0, section = geom->sections; i < geom->num_sections; i++, section++) { size += WriteXKMGeomSection(file, result, section); } } if (geom->doodads) { XkbDoodadPtr doodad; for (i = 0, doodad = geom->doodads; i < geom->num_doodads; i++, doodad++) { size += WriteXKMGeomDoodad(file, result, doodad); } } if (geom->key_aliases) { tmp = fwrite(geom->key_aliases, 2 * XkbKeyNameLength, geom->num_key_aliases, file); size += tmp * (2 * XkbKeyNameLength); } return size; } /***====================================================================***/ /*ARGSUSED*/ static int GetXKMKeyNamesTOC(XkbFileInfo *result, XkmInfo *info, int max_toc, xkmSectionInfo *toc_rtrn) { int num_toc; int total_size; total_size = num_toc = 0; if (SizeXKMKeycodes(result, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; return num_toc; } /*ARGSUSED*/ static int GetXKMTypesTOC(XkbFileInfo *result, XkmInfo *info, int max_toc, xkmSectionInfo *toc_rtrn) { int num_toc; int total_size; total_size = num_toc = 0; if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size)) num_toc++; return num_toc; } /*ARGSUSED*/ static int GetXKMCompatMapTOC(XkbFileInfo *result, XkmInfo *info, int max_toc, xkmSectionInfo *toc_rtrn) { int num_toc; int total_size; total_size = num_toc = 0; if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMCompatMap(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; return num_toc; } /*ARGSUSED*/ static int GetXKMSemanticsTOC(XkbFileInfo *result, XkmInfo *info, int max_toc, xkmSectionInfo *toc_rtrn) { int num_toc; int total_size; total_size = num_toc = 0; if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMCompatMap(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; return num_toc; } /*ARGSUSED*/ static int GetXKMLayoutTOC(XkbFileInfo *result, XkmInfo *info, int max_toc, xkmSectionInfo *toc_rtrn) { int num_toc; int total_size; total_size = num_toc = 0; if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMKeycodes(result, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMSymbols(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMGeometry(result, &toc_rtrn[num_toc], &total_size)) num_toc++; return num_toc; } /*ARGSUSED*/ static int GetXKMKeymapTOC(XkbFileInfo *result, XkmInfo *info, int max_toc, xkmSectionInfo *toc_rtrn) { int num_toc; int total_size; total_size = num_toc = 0; if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMKeycodes(result, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMCompatMap(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMSymbols(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size)) num_toc++; if (SizeXKMGeometry(result, &toc_rtrn[num_toc], &total_size)) num_toc++; return num_toc; } /*ARGSUSED*/ static int GetXKMGeometryTOC(XkbFileInfo *result, XkmInfo *info, int max_toc, xkmSectionInfo *toc_rtrn) { int num_toc; int total_size; total_size = num_toc = 0; if (SizeXKMGeometry(result, &toc_rtrn[num_toc], &total_size)) num_toc++; return num_toc; } static Bool WriteXKMFile(FILE *file, XkbFileInfo *result, int num_toc, xkmSectionInfo *toc, XkmInfo *info) { register int i; unsigned tmp, size, total = 0; for (i = 0; i < num_toc; i++) { tmp = fwrite(&toc[i], SIZEOF(xkmSectionInfo), 1, file); total += tmp * SIZEOF(xkmSectionInfo); switch (toc[i].type) { case XkmTypesIndex: size = WriteXKMKeyTypes(file, result); break; case XkmCompatMapIndex: size = WriteXKMCompatMap(file, result, info); break; case XkmSymbolsIndex: size = WriteXKMSymbols(file, result, info); break; case XkmIndicatorsIndex: size = WriteXKMIndicators(file, result, info); break; case XkmKeyNamesIndex: size = WriteXKMKeycodes(file, result); break; case XkmGeometryIndex: size = WriteXKMGeometry(file, result); break; case XkmVirtualModsIndex: size = WriteXKMVirtualMods(file, result, info); break; default: _XkbLibError(_XkbErrIllegalTOCType, "WriteXKMFile", toc[i].type); return False; } size += SIZEOF(xkmSectionInfo); if (size != toc[i].size) { _XkbLibError(_XkbErrBadLength, XkbConfigText(toc[i].type, XkbMessage), size - toc[i].size); return False; } } return True; } #define MAX_TOC 16 Bool XkbWriteXKMFile(FILE *out, XkbFileInfo *result) { Bool ok; XkbDescPtr xkb; XkmInfo info; int size_toc, i; unsigned hdr, present; xkmFileInfo fileInfo; xkmSectionInfo toc[MAX_TOC]; int (*getTOC) (XkbFileInfo * /* result */ , XkmInfo * /* info */ , int /* max_to */ , xkmSectionInfo * /* toc_rtrn */ ); switch (result->type) { case XkmKeyNamesIndex: getTOC = GetXKMKeyNamesTOC; break; case XkmTypesIndex: getTOC = GetXKMTypesTOC; break; case XkmCompatMapIndex: getTOC = GetXKMCompatMapTOC; break; case XkmSemanticsFile: getTOC = GetXKMSemanticsTOC; break; case XkmLayoutFile: getTOC = GetXKMLayoutTOC; break; case XkmKeymapFile: getTOC = GetXKMKeymapTOC; break; case XkmGeometryFile: case XkmGeometryIndex: getTOC = GetXKMGeometryTOC; break; default: _XkbLibError(_XkbErrIllegalContents, XkbConfigText(result->type, XkbMessage), 0); return False; } xkb = result->xkb; bzero((char *) &info, sizeof(XkmInfo)); size_toc = (*getTOC) (result, &info, MAX_TOC, toc); if (size_toc < 1) { _XkbLibError(_XkbErrEmptyFile, "XkbWriteXKMFile", 0); return False; } if (out == NULL) { _XkbLibError(_XkbErrFileCannotOpen, "XkbWriteXKMFile", 0); return False; } for (i = present = 0; i < size_toc; i++) { toc[i].offset += 4 + SIZEOF(xkmFileInfo); toc[i].offset += (size_toc * SIZEOF(xkmSectionInfo)); if (toc[i].type <= XkmLastIndex) { present |= (1 << toc[i].type); } #ifdef DEBUG else { fprintf(stderr, "Illegal section type %d\n", toc[i].type); fprintf(stderr, "Ignored\n"); } #endif } hdr = (('x' << 24) | ('k' << 16) | ('m' << 8) | XkmFileVersion); xkmPutCARD32(out, (unsigned long) hdr); fileInfo.type = result->type; fileInfo.min_kc = xkb->min_key_code; fileInfo.max_kc = xkb->max_key_code; fileInfo.num_toc = size_toc; fileInfo.present = present; fileInfo.pad = 0; fwrite(&fileInfo, SIZEOF(xkmFileInfo), 1, out); fwrite(toc, SIZEOF(xkmSectionInfo), size_toc, out); ok = WriteXKMFile(out, result, size_toc, toc, &info); return ok; }