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_CONFIG_H
28#include <config.h>
29#endif
30#include <stdio.h>
31#include <ctype.h>
32#include <stdlib.h>
33#include <X11/Xfuncs.h>
34#include <X11/Xlib.h>
35#include <X11/XKBlib.h>
36#include <X11/extensions/XKBgeom.h>
37
38#include "XKMformat.h"
39#include "XKBfileInt.h"
40
41typedef struct _XkmInfo {
42    unsigned short bound_vmods;
43    unsigned short named_vmods;
44    unsigned char  num_bound;
45    unsigned char  group_compat;
46    unsigned short num_group_compat;
47    unsigned short num_leds;
48    int            total_vmodmaps;
49} XkmInfo;
50
51/***====================================================================***/
52
53#define	xkmPutCARD8(f,v)	(putc(v,f),1)
54
55static int
56xkmPutCARD16(FILE *file, unsigned val)
57{
58    CARD16 tmp = val;
59
60    fwrite(&tmp, 2, 1, file);
61    return 2;
62}
63
64static int
65xkmPutCARD32(FILE *file, unsigned long val)
66{
67    CARD32 tmp = val;
68
69    fwrite(&tmp, 4, 1, file);
70    return 4;
71}
72
73static int
74xkmPutPadding(FILE *file, unsigned pad)
75{
76    int i;
77
78    for (i = 0; i < pad; i++) {
79        putc('\0', file);
80    }
81    return pad;
82}
83
84static int
85xkmPutCountedBytes(FILE *file, char *ptr, unsigned count)
86{
87    register int nOut;
88    register unsigned pad;
89
90    if (count == 0)
91        return xkmPutCARD32(file, (unsigned long) 0);
92
93    xkmPutCARD16(file, count);
94    nOut = fwrite(ptr, 1, count, file);
95    if (nOut < 0)
96        return 2;
97    nOut = count + 2;
98    pad = XkbPaddedSize(nOut) - nOut;
99    if (pad)
100        xkmPutPadding(file, pad);
101    return nOut + pad;
102}
103
104static unsigned
105xkmSizeCountedString(char *str)
106{
107    if (str == NULL)
108        return 4;
109    return XkbPaddedSize(strlen(str) + 2);
110}
111
112static int
113xkmPutCountedString(FILE *file, char *str)
114{
115    if (str == NULL)
116        return xkmPutCARD32(file, (unsigned long) 0);
117    return xkmPutCountedBytes(file, str, strlen(str));
118}
119
120#define	xkmSizeCountedAtomString(d,a)	\
121	xkmSizeCountedString(XkbAtomGetString((d),(a)))
122
123#define	xkmPutCountedAtomString(d,f,a)	\
124	xkmPutCountedString((f),XkbAtomGetString((d),(a)))
125
126/***====================================================================***/
127
128static unsigned
129SizeXKMVirtualMods(XkbFileInfo *result, XkmInfo *info,
130                   xkmSectionInfo *toc, int *offset_inout)
131{
132    Display *dpy;
133    XkbDescPtr xkb;
134    unsigned nBound, bound;
135    unsigned nNamed, named, szNames;
136    register unsigned i, bit;
137
138    xkb = result->xkb;
139    if ((!xkb) || (!xkb->names) || (!xkb->server)) {
140        _XkbLibError(_XkbErrMissingVMods, "SizeXKMVirtualMods", 0);
141        return 0;
142    }
143    dpy = xkb->dpy;
144    bound = named = 0;
145    for (i = nBound = nNamed = szNames = 0, bit = 1; i < XkbNumVirtualMods;
146         i++, bit <<= 1) {
147        if (xkb->server->vmods[i] != XkbNoModifierMask) {
148            bound |= bit;
149            nBound++;
150        }
151        if (xkb->names->vmods[i] != None) {
152            named |= bit;
153            szNames += xkmSizeCountedAtomString(dpy, xkb->names->vmods[i]);
154            nNamed++;
155        }
156    }
157    info->num_bound = nBound;
158    info->bound_vmods = bound;
159    info->named_vmods = named;
160    if ((nBound == 0) && (nNamed == 0))
161        return 0;
162    toc->type = XkmVirtualModsIndex;
163    toc->format = MSBFirst;
164    toc->size = 4 + XkbPaddedSize(nBound) + szNames + SIZEOF(xkmSectionInfo);
165    toc->offset = *offset_inout;
166    (*offset_inout) += toc->size;
167    return 1;
168}
169
170static unsigned
171WriteXKMVirtualMods(FILE *file, XkbFileInfo *result, XkmInfo *info)
172{
173    register unsigned int i, bit;
174    XkbDescPtr xkb;
175    Display *dpy;
176    unsigned size = 0;
177
178    xkb = result->xkb;
179    dpy = xkb->dpy;
180    size += xkmPutCARD16(file, info->bound_vmods);
181    size += xkmPutCARD16(file, info->named_vmods);
182    for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
183        if (info->bound_vmods & bit)
184            size += xkmPutCARD8(file, xkb->server->vmods[i]);
185    }
186    if ((i = XkbPaddedSize(info->num_bound) - info->num_bound) > 0)
187        size += xkmPutPadding(file, i);
188    for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
189        if (info->named_vmods & bit) {
190            register char *name;
191
192            name = XkbAtomGetString(dpy, xkb->names->vmods[i]);
193            size += xkmPutCountedString(file, name);
194        }
195    }
196    return size;
197}
198
199/***====================================================================***/
200
201static unsigned
202SizeXKMKeycodes(XkbFileInfo *result, xkmSectionInfo *toc, int *offset_inout)
203{
204    XkbDescPtr xkb;
205    Atom kcName;
206    int size = 0;
207    Display *dpy;
208
209    xkb = result->xkb;
210    if ((!xkb) || (!xkb->names) || (!xkb->names->keys)) {
211        _XkbLibError(_XkbErrMissingNames, "SizeXKMKeycodes", 0);
212        return 0;
213    }
214    dpy = xkb->dpy;
215    kcName = xkb->names->keycodes;
216    size += 4;                  /* min and max keycode */
217    size += xkmSizeCountedAtomString(dpy, kcName);
218    size += XkbNumKeys(xkb) * sizeof(XkbKeyNameRec);
219    if (xkb->names->num_key_aliases > 0) {
220        if (xkb->names->key_aliases != NULL)
221            size += xkb->names->num_key_aliases * sizeof(XkbKeyAliasRec);
222        else
223            xkb->names->num_key_aliases = 0;
224    }
225    toc->type = XkmKeyNamesIndex;
226    toc->format = MSBFirst;
227    toc->size = size + SIZEOF(xkmSectionInfo);
228    toc->offset = (*offset_inout);
229    (*offset_inout) += toc->size;
230    return 1;
231}
232
233static unsigned
234WriteXKMKeycodes(FILE *file, XkbFileInfo *result)
235{
236    XkbDescPtr xkb;
237    Atom kcName;
238    char *start;
239    Display *dpy;
240    unsigned tmp, size = 0;
241
242    xkb = result->xkb;
243    dpy = xkb->dpy;
244    kcName = xkb->names->keycodes;
245    start = xkb->names->keys[xkb->min_key_code].name;
246
247    size += xkmPutCountedString(file, XkbAtomGetString(dpy, kcName));
248    size += xkmPutCARD8(file, xkb->min_key_code);
249    size += xkmPutCARD8(file, xkb->max_key_code);
250    size += xkmPutCARD8(file, xkb->names->num_key_aliases);
251    size += xkmPutPadding(file, 1);
252    tmp = fwrite(start, sizeof(XkbKeyNameRec), XkbNumKeys(xkb), file);
253    size += tmp * sizeof(XkbKeyNameRec);
254    if (xkb->names->num_key_aliases > 0) {
255        tmp = fwrite((char *) xkb->names->key_aliases,
256                     sizeof(XkbKeyAliasRec), xkb->names->num_key_aliases, file);
257        size += tmp * sizeof(XkbKeyAliasRec);
258    }
259    return size;
260}
261
262/***====================================================================***/
263
264static unsigned
265SizeXKMKeyTypes(XkbFileInfo *result, xkmSectionInfo *toc, int *offset_inout)
266{
267    register unsigned i, n, size;
268    XkbKeyTypePtr type;
269    XkbDescPtr xkb;
270    Display *dpy;
271    char *name;
272
273    xkb = result->xkb;
274    if ((!xkb) || (!xkb->map) || (!xkb->map->types)) {
275        _XkbLibError(_XkbErrMissingTypes, "SizeXKBKeyTypes", 0);
276        return 0;
277    }
278    dpy = xkb->dpy;
279    if (xkb->map->num_types < XkbNumRequiredTypes) {
280        _XkbLibError(_XkbErrMissingReqTypes, "SizeXKBKeyTypes", 0);
281        return 0;
282    }
283    if (xkb->names)
284        name = XkbAtomGetString(dpy, xkb->names->types);
285    else
286        name = NULL;
287    size = xkmSizeCountedString(name);
288    size += 4;                  /* room for # of key types + padding */
289    for (i = 0, type = xkb->map->types; i < xkb->map->num_types; i++, type++) {
290        size += SIZEOF(xkmKeyTypeDesc);
291        size += SIZEOF(xkmKTMapEntryDesc) * type->map_count;
292        size += xkmSizeCountedAtomString(dpy, type->name);
293        if (type->preserve)
294            size += SIZEOF(xkmModsDesc) * type->map_count;
295        if (type->level_names) {
296            Atom *names;
297
298            names = type->level_names;
299            for (n = 0; n < (unsigned) type->num_levels; n++) {
300                size += xkmSizeCountedAtomString(dpy, names[n]);
301            }
302        }
303    }
304    toc->type = XkmTypesIndex;
305    toc->format = MSBFirst;
306    toc->size = size + SIZEOF(xkmSectionInfo);
307    toc->offset = (*offset_inout);
308    (*offset_inout) += toc->size;
309    return 1;
310}
311
312static unsigned
313WriteXKMKeyTypes(FILE *file, XkbFileInfo *result)
314{
315    register unsigned i, n;
316    XkbDescPtr xkb;
317    XkbKeyTypePtr type;
318    xkmKeyTypeDesc wire;
319    XkbKTMapEntryPtr entry;
320    xkmKTMapEntryDesc wire_entry;
321    Atom *names;
322    Display *dpy;
323    unsigned tmp, size = 0;
324    char *name;
325
326    xkb = result->xkb;
327    dpy = xkb->dpy;
328    if (xkb->names)
329        name = XkbAtomGetString(dpy, xkb->names->types);
330    else
331        name = NULL;
332    size += xkmPutCountedString(file, name);
333    size += xkmPutCARD16(file, xkb->map->num_types);
334    size += xkmPutPadding(file, 2);
335    type = xkb->map->types;
336    for (i = 0; i < xkb->map->num_types; i++, type++) {
337        wire.realMods = type->mods.real_mods;
338        wire.virtualMods = type->mods.vmods;
339        wire.numLevels = type->num_levels;
340        wire.nMapEntries = type->map_count;
341        wire.preserve = (type->preserve != NULL);
342        if (type->level_names != NULL)
343            wire.nLevelNames = type->num_levels;
344        else
345            wire.nLevelNames = 0;
346        tmp = fwrite(&wire, SIZEOF(xkmKeyTypeDesc), 1, file);
347        size += tmp * SIZEOF(xkmKeyTypeDesc);
348        for (n = 0, entry = type->map; n < type->map_count; n++, entry++) {
349            wire_entry.level = entry->level;
350            wire_entry.realMods = entry->mods.real_mods;
351            wire_entry.virtualMods = entry->mods.vmods;
352            tmp = fwrite(&wire_entry, SIZEOF(xkmKTMapEntryDesc), 1, file);
353            size += tmp * SIZEOF(xkmKTMapEntryDesc);
354        }
355        size += xkmPutCountedString(file, XkbAtomGetString(dpy, type->name));
356        if (type->preserve) {
357            xkmModsDesc p_entry;
358
359            XkbModsPtr pre;
360
361            for (n = 0, pre = type->preserve; n < type->map_count; n++, pre++) {
362                p_entry.realMods = pre->real_mods;
363                p_entry.virtualMods = pre->vmods;
364                tmp = fwrite(&p_entry, SIZEOF(xkmModsDesc), 1, file);
365                size += tmp * SIZEOF(xkmModsDesc);
366            }
367        }
368        if (type->level_names != NULL) {
369            names = type->level_names;
370            for (n = 0; n < wire.nLevelNames; n++) {
371                size +=
372                    xkmPutCountedString(file, XkbAtomGetString(dpy, names[n]));
373            }
374        }
375    }
376    return size;
377}
378
379/***====================================================================***/
380
381static unsigned
382SizeXKMCompatMap(XkbFileInfo *result, XkmInfo *info,
383                 xkmSectionInfo *toc, int *offset_inout)
384{
385    XkbDescPtr xkb;
386    char *name;
387    int size;
388    register int i;
389    unsigned groups, nGroups;
390    Display *dpy;
391
392    xkb = result->xkb;
393    if ((!xkb) || (!xkb->compat) || (!xkb->compat->sym_interpret)) {
394        _XkbLibError(_XkbErrMissingCompatMap, "SizeXKMCompatMap", 0);
395        return 0;
396    }
397    dpy = xkb->dpy;
398    if (xkb->names)
399        name = XkbAtomGetString(dpy, xkb->names->compat);
400    else
401        name = NULL;
402
403    for (i = groups = nGroups = 0; i < XkbNumKbdGroups; i++) {
404        if ((xkb->compat->groups[i].real_mods != 0) ||
405            (xkb->compat->groups[i].vmods != 0)) {
406            groups |= (1 << i);
407            nGroups++;
408        }
409    }
410    info->group_compat = groups;
411    info->num_group_compat = nGroups;
412    size = 4;                   /* room for num_si and group_compat mask */
413    size += xkmSizeCountedString(name);
414    size += (SIZEOF(xkmSymInterpretDesc) * xkb->compat->num_si);
415    size += (SIZEOF(xkmModsDesc) * nGroups);
416    toc->type = XkmCompatMapIndex;
417    toc->format = MSBFirst;
418    toc->size = size + SIZEOF(xkmSectionInfo);
419    toc->offset = (*offset_inout);
420    (*offset_inout) += toc->size;
421    return 1;
422}
423
424static unsigned
425WriteXKMCompatMap(FILE *file, XkbFileInfo *result, XkmInfo *info)
426{
427    register unsigned i;
428    char *name;
429    XkbDescPtr xkb;
430    XkbSymInterpretPtr interp;
431    xkmSymInterpretDesc wire;
432    Display *dpy;
433    unsigned tmp, size = 0;
434
435    xkb = result->xkb;
436    dpy = xkb->dpy;
437    if (xkb->names)
438        name = XkbAtomGetString(dpy, xkb->names->compat);
439    else
440        name = NULL;
441    size += xkmPutCountedString(file, name);
442    size += xkmPutCARD16(file, xkb->compat->num_si);
443    size += xkmPutCARD8(file, info->group_compat);
444    size += xkmPutPadding(file, 1);
445    interp = xkb->compat->sym_interpret;
446    for (i = 0; i < xkb->compat->num_si; i++, interp++) {
447        wire.sym = interp->sym;
448        wire.mods = interp->mods;
449        wire.match = interp->match;
450        wire.virtualMod = interp->virtual_mod;
451        wire.flags = interp->flags;
452        wire.actionType = interp->act.type;
453        wire.actionData[0] = interp->act.data[0];
454        wire.actionData[1] = interp->act.data[1];
455        wire.actionData[2] = interp->act.data[2];
456        wire.actionData[3] = interp->act.data[3];
457        wire.actionData[4] = interp->act.data[4];
458        wire.actionData[5] = interp->act.data[5];
459        wire.actionData[6] = interp->act.data[6];
460        tmp = fwrite(&wire, SIZEOF(xkmSymInterpretDesc), 1, file);
461        size += tmp * SIZEOF(xkmSymInterpretDesc);
462    }
463    if (info->group_compat) {
464        register unsigned bit;
465
466        xkmModsDesc modsWire;
467
468        for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
469            if (info->group_compat & bit) {
470                modsWire.realMods = xkb->compat->groups[i].real_mods;
471                modsWire.virtualMods = xkb->compat->groups[i].vmods;
472                fwrite(&modsWire, SIZEOF(xkmModsDesc), 1, file);
473                size += SIZEOF(xkmModsDesc);
474            }
475        }
476    }
477    return size;
478}
479
480/***====================================================================***/
481
482static unsigned
483SizeXKMSymbols(XkbFileInfo *result, XkmInfo *info,
484               xkmSectionInfo *toc, int *offset_inout)
485{
486    Display *dpy;
487    XkbDescPtr xkb;
488    unsigned size;
489    register int i, nSyms;
490    char *name;
491
492    xkb = result->xkb;
493    if ((!xkb) || (!xkb->map) || ((!xkb->map->syms))) {
494        _XkbLibError(_XkbErrMissingSymbols, "SizeXKMSymbols", 0);
495        return 0;
496    }
497    dpy = xkb->dpy;
498    if (xkb->names && (xkb->names->symbols != None))
499        name = XkbAtomGetString(dpy, xkb->names->symbols);
500    else
501        name = NULL;
502    size = xkmSizeCountedString(name);
503    size += 4;                  /* min and max keycode, group names mask */
504    for (i = 0; i < XkbNumKbdGroups; i++) {
505        if (xkb->names->groups[i] != None)
506            size += xkmSizeCountedAtomString(dpy, xkb->names->groups[i]);
507    }
508    info->total_vmodmaps = 0;
509    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
510        nSyms = XkbKeyNumSyms(xkb, i);
511        size += SIZEOF(xkmKeySymMapDesc) + (nSyms * 4);
512        if (xkb->server) {
513            if (xkb->server->explicit[i] & XkbExplicitKeyTypesMask) {
514                register int g;
515
516                for (g = XkbKeyNumGroups(xkb, i) - 1; g >= 0; g--) {
517                    if (xkb->server->explicit[i] & (1 << g)) {
518                        XkbKeyTypePtr type;
519                        char *name;
520
521                        type = XkbKeyKeyType(xkb, i, g);
522                        name = XkbAtomGetString(dpy, type->name);
523                        if (name != NULL)
524                            size += xkmSizeCountedString(name);
525                    }
526                }
527            }
528            if (XkbKeyHasActions(xkb, i))
529                size += nSyms * SIZEOF(xkmActionDesc);
530            if (xkb->server->behaviors[i].type != XkbKB_Default)
531                size += SIZEOF(xkmBehaviorDesc);
532            if (xkb->server->vmodmap && (xkb->server->vmodmap[i] != 0))
533                info->total_vmodmaps++;
534        }
535    }
536    size += info->total_vmodmaps * SIZEOF(xkmVModMapDesc);
537    toc->type = XkmSymbolsIndex;
538    toc->format = MSBFirst;
539    toc->size = size + SIZEOF(xkmSectionInfo);
540    toc->offset = (*offset_inout);
541    (*offset_inout) += toc->size;
542    return 1;
543}
544
545static unsigned
546WriteXKMSymbols(FILE *file, XkbFileInfo *result, XkmInfo *info)
547{
548    Display *dpy;
549    XkbDescPtr xkb;
550    register int i, n;
551    xkmKeySymMapDesc wireMap;
552    char *name;
553    unsigned tmp, size = 0;
554
555    xkb = result->xkb;
556    dpy = xkb->dpy;
557    if (xkb->names && (xkb->names->symbols != None))
558        name = XkbAtomGetString(dpy, xkb->names->symbols);
559    else
560        name = NULL;
561    size += xkmPutCountedString(file, name);
562    for (tmp = i = 0; i < XkbNumKbdGroups; i++) {
563        if (xkb->names->groups[i] != None)
564            tmp |= (1 << i);
565    }
566    size += xkmPutCARD8(file, xkb->min_key_code);
567    size += xkmPutCARD8(file, xkb->max_key_code);
568    size += xkmPutCARD8(file, tmp);
569    size += xkmPutCARD8(file, info->total_vmodmaps);
570    for (i = 0, n = 1; i < XkbNumKbdGroups; i++, n <<= 1) {
571        if ((tmp & n) == 0)
572            continue;
573        size += xkmPutCountedAtomString(dpy, file, xkb->names->groups[i]);
574    }
575    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
576        char *typeName[XkbNumKbdGroups];
577
578        wireMap.width = XkbKeyGroupsWidth(xkb, i);
579        wireMap.num_groups = XkbKeyGroupInfo(xkb, i);
580        if (xkb->map && xkb->map->modmap)
581            wireMap.modifier_map = xkb->map->modmap[i];
582        else
583            wireMap.modifier_map = 0;
584        wireMap.flags = 0;
585        bzero((char *) typeName, XkbNumKbdGroups * sizeof(char *));
586        if (xkb->server) {
587            if (xkb->server->explicit[i] & XkbExplicitKeyTypesMask) {
588                register int g;
589
590                for (g = 0; g < XkbKeyNumGroups(xkb, i); g++) {
591                    if (xkb->server->explicit[i] & (1 << g)) {
592                        XkbKeyTypePtr type;
593
594                        type = XkbKeyKeyType(xkb, i, g);
595                        typeName[g] = XkbAtomGetString(dpy, type->name);
596                        if (typeName[g] != NULL)
597                            wireMap.flags |= (1 << g);
598                    }
599                }
600            }
601            if (XkbKeyHasActions(xkb, i))
602                wireMap.flags |= XkmKeyHasActions;
603            if (xkb->server->behaviors[i].type != XkbKB_Default)
604                wireMap.flags |= XkmKeyHasBehavior;
605            if ((xkb->server->explicit[i] & XkbExplicitAutoRepeatMask) &&
606                (xkb->ctrls != NULL)) {
607                if (xkb->ctrls->per_key_repeat[(i / 8)] & (1 << (i % 8)))
608                    wireMap.flags |= XkmRepeatingKey;
609                else
610                    wireMap.flags |= XkmNonRepeatingKey;
611            }
612        }
613        tmp = fwrite(&wireMap, SIZEOF(xkmKeySymMapDesc), 1, file);
614        size += tmp * SIZEOF(xkmKeySymMapDesc);
615        if (xkb->server->explicit[i] & XkbExplicitKeyTypesMask) {
616            register int g;
617
618            for (g = 0; g < XkbNumKbdGroups; g++) {
619                if (typeName[g] != NULL)
620                    size += xkmPutCountedString(file, typeName[g]);
621            }
622        }
623        if (XkbNumGroups(wireMap.num_groups) > 0) {
624            KeySym *sym;
625
626            sym = XkbKeySymsPtr(xkb, i);
627            for (n = XkbKeyNumSyms(xkb, i); n > 0; n--, sym++) {
628                size += xkmPutCARD32(file, (CARD32) *sym);
629            }
630            if (wireMap.flags & XkmKeyHasActions) {
631                XkbAction *act;
632
633                act = XkbKeyActionsPtr(xkb, i);
634                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, act++) {
635                    tmp = fwrite(act, SIZEOF(xkmActionDesc), 1, file);
636                    size += tmp * SIZEOF(xkmActionDesc);
637                }
638            }
639        }
640        if (wireMap.flags & XkmKeyHasBehavior) {
641            xkmBehaviorDesc b;
642
643            b.type = xkb->server->behaviors[i].type;
644            b.data = xkb->server->behaviors[i].data;
645            tmp = fwrite(&b, SIZEOF(xkmBehaviorDesc), 1, file);
646            size += tmp * SIZEOF(xkmBehaviorDesc);
647        }
648    }
649    if (info->total_vmodmaps > 0) {
650        xkmVModMapDesc v;
651
652        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
653            if (xkb->server->vmodmap[i] != 0) {
654                v.key = i;
655                v.vmods = xkb->server->vmodmap[i];
656                tmp = fwrite(&v, SIZEOF(xkmVModMapDesc), 1, file);
657                size += tmp * SIZEOF(xkmVModMapDesc);
658            }
659        }
660    }
661    return size;
662}
663
664/***====================================================================***/
665
666static unsigned
667SizeXKMIndicators(XkbFileInfo *result, XkmInfo *info,
668                  xkmSectionInfo *toc, int *offset_inout)
669{
670    Display *dpy;
671    XkbDescPtr xkb;
672    unsigned size;
673    register unsigned i, nLEDs;
674
675    xkb = result->xkb;
676    if ((xkb == NULL) || (xkb->indicators == NULL)) {
677/*	_XkbLibError(_XkbErrMissingIndicators,"SizeXKMIndicators",0);*/
678        return 0;
679    }
680    dpy = xkb->dpy;
681    nLEDs = 0;
682    size = 8; /* number of indicator maps/physical indicators */
683    if (xkb->indicators != NULL) {
684        for (i = 0; i < XkbNumIndicators; i++) {
685            XkbIndicatorMapPtr map = &xkb->indicators->maps[i];
686
687            if ((map->flags != 0) || (map->which_groups != 0) ||
688                (map->groups != 0) || (map->which_mods != 0) ||
689                (map->mods.real_mods != 0) || (map->mods.vmods != 0) ||
690                (map->ctrls != 0) ||
691                (xkb->names && (xkb->names->indicators[i] != None))) {
692                char *name;
693
694                if (xkb->names && xkb->names->indicators[i] != None) {
695                    name = XkbAtomGetString(dpy, xkb->names->indicators[i]);
696                }
697                else
698                    name = NULL;
699                size += xkmSizeCountedString(name);
700                size += SIZEOF(xkmIndicatorMapDesc);
701                nLEDs++;
702            }
703        }
704    }
705    info->num_leds = nLEDs;
706    toc->type = XkmIndicatorsIndex;
707    toc->format = MSBFirst;
708    toc->size = size + SIZEOF(xkmSectionInfo);
709    toc->offset = (*offset_inout);
710    (*offset_inout) += toc->size;
711    return 1;
712}
713
714static unsigned
715WriteXKMIndicators(FILE *file, XkbFileInfo *result, XkmInfo *info)
716{
717    Display *dpy;
718    XkbDescPtr xkb;
719    register unsigned i;
720    xkmIndicatorMapDesc wire;
721    unsigned tmp, size = 0;
722
723    xkb = result->xkb;
724    dpy = xkb->dpy;
725    size += xkmPutCARD8(file, info->num_leds);
726    size += xkmPutPadding(file, 3);
727    size += xkmPutCARD32(file, xkb->indicators->phys_indicators);
728    if (xkb->indicators != NULL) {
729        for (i = 0; i < XkbNumIndicators; i++) {
730            XkbIndicatorMapPtr map = &xkb->indicators->maps[i];
731
732            if ((map->flags != 0) || (map->which_groups != 0) ||
733                (map->groups != 0) || (map->which_mods != 0) ||
734                (map->mods.real_mods != 0) || (map->mods.vmods != 0) ||
735                (map->ctrls != 0) || (xkb->names &&
736                                      (xkb->names->indicators[i] != None))) {
737                char *name;
738
739                if (xkb->names && xkb->names->indicators[i] != None) {
740                    name = XkbAtomGetString(dpy, xkb->names->indicators[i]);
741                }
742                else
743                    name = NULL;
744                size += xkmPutCountedString(file, name);
745                wire.indicator = i + 1;
746                wire.flags = map->flags;
747                wire.which_mods = map->which_mods;
748                wire.real_mods = map->mods.real_mods;
749                wire.vmods = map->mods.vmods;
750                wire.which_groups = map->which_groups;
751                wire.groups = map->groups;
752                wire.ctrls = map->ctrls;
753                tmp = fwrite(&wire, SIZEOF(xkmIndicatorMapDesc), 1, file);
754                size += tmp * SIZEOF(xkmIndicatorMapDesc);
755            }
756        }
757    }
758    return size;
759}
760
761/***====================================================================***/
762
763static unsigned
764SizeXKMGeomDoodad(XkbFileInfo *result, XkbDoodadPtr doodad)
765{
766    unsigned size;
767
768    size = SIZEOF(xkmAnyDoodadDesc);
769    size += xkmSizeCountedAtomString(result->xkb->dpy, doodad->any.name);
770    if (doodad->any.type == XkbTextDoodad) {
771        size += xkmSizeCountedString(doodad->text.text);
772        size += xkmSizeCountedString(doodad->text.font);
773    }
774    else if (doodad->any.type == XkbLogoDoodad) {
775        size += xkmSizeCountedString(doodad->logo.logo_name);
776    }
777    return size;
778}
779
780static unsigned
781SizeXKMGeomSection(XkbFileInfo *result, XkbSectionPtr section)
782{
783    register int i;
784    unsigned size;
785
786    size = SIZEOF(xkmSectionDesc);
787    size += xkmSizeCountedAtomString(result->xkb->dpy, section->name);
788    if (section->rows) {
789        XkbRowPtr row;
790
791        for (row = section->rows, i = 0; i < section->num_rows; i++, row++) {
792            size += SIZEOF(xkmRowDesc);
793            size += row->num_keys * SIZEOF(xkmKeyDesc);
794        }
795    }
796    if (section->doodads) {
797        XkbDoodadPtr doodad;
798
799        for (doodad = section->doodads, i = 0; i < section->num_doodads;
800             i++, doodad++) {
801            size += SizeXKMGeomDoodad(result, doodad);
802        }
803    }
804    if (section->overlays) {
805        XkbOverlayPtr ol;
806
807        for (ol = section->overlays, i = 0; i < section->num_overlays;
808             i++, ol++) {
809            register int r;
810            XkbOverlayRowPtr row;
811
812            size += xkmSizeCountedAtomString(result->xkb->dpy, ol->name);
813            size += SIZEOF(xkmOverlayDesc);
814            for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
815                size += SIZEOF(xkmOverlayRowDesc);
816                size += row->num_keys * SIZEOF(xkmOverlayKeyDesc);
817            }
818        }
819    }
820    return size;
821}
822
823static unsigned
824SizeXKMGeometry(XkbFileInfo *result, xkmSectionInfo *toc, int *offset_inout)
825{
826    register int i;
827    Display *dpy;
828    XkbDescPtr xkb;
829    XkbGeometryPtr geom;
830    unsigned size;
831
832    xkb = result->xkb;
833    if ((!xkb) || (!xkb->geom))
834        return 0;
835    dpy = xkb->dpy;
836    geom = xkb->geom;
837    size = xkmSizeCountedAtomString(dpy, geom->name);
838    size += SIZEOF(xkmGeometryDesc);
839    size += xkmSizeCountedString(geom->label_font);
840    if (geom->properties) {
841        XkbPropertyPtr prop;
842
843        for (i = 0, prop = geom->properties; i < geom->num_properties;
844             i++, prop++) {
845            size += xkmSizeCountedString(prop->name);
846            size += xkmSizeCountedString(prop->value);
847        }
848    }
849    if (geom->colors) {
850        XkbColorPtr color;
851
852        for (i = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
853            size += xkmSizeCountedString(color->spec);
854        }
855    }
856    if (geom->shapes) {
857        XkbShapePtr shape;
858
859        for (i = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
860            register int n;
861            register XkbOutlinePtr ol;
862
863            size += xkmSizeCountedAtomString(dpy, shape->name);
864            size += SIZEOF(xkmShapeDesc);
865            for (n = 0, ol = shape->outlines; n < shape->num_outlines;
866                 n++, ol++) {
867                size += SIZEOF(xkmOutlineDesc);
868                size += ol->num_points * SIZEOF(xkmPointDesc);
869            }
870        }
871    }
872    if (geom->sections) {
873        XkbSectionPtr section;
874
875        for (i = 0, section = geom->sections; i < geom->num_sections;
876             i++, section++) {
877            size += SizeXKMGeomSection(result, section);
878        }
879    }
880    if (geom->doodads) {
881        XkbDoodadPtr doodad;
882
883        for (i = 0, doodad = geom->doodads; i < geom->num_doodads;
884             i++, doodad++) {
885            size += SizeXKMGeomDoodad(result, doodad);
886        }
887    }
888    if (geom->key_aliases) {
889        size += geom->num_key_aliases * (XkbKeyNameLength * 2);
890    }
891    toc->type = XkmGeometryIndex;
892    toc->format = MSBFirst;
893    toc->size = size + SIZEOF(xkmSectionInfo);
894    toc->offset = (*offset_inout);
895    (*offset_inout) += toc->size;
896    return 1;
897}
898
899static unsigned
900WriteXKMGeomDoodad(FILE *file, XkbFileInfo *result, XkbDoodadPtr doodad)
901{
902    Display *dpy;
903    XkbDescPtr xkb;
904    xkmDoodadDesc doodadWire;
905    unsigned tmp, size = 0;
906
907    xkb = result->xkb;
908    dpy = xkb->dpy;
909    bzero((char *) &doodadWire, sizeof(doodadWire));
910    doodadWire.any.type = doodad->any.type;
911    doodadWire.any.priority = doodad->any.priority;
912    doodadWire.any.top = doodad->any.top;
913    doodadWire.any.left = doodad->any.left;
914    switch (doodad->any.type) {
915    case XkbOutlineDoodad:
916    case XkbSolidDoodad:
917        doodadWire.shape.angle = doodad->shape.angle;
918        doodadWire.shape.color_ndx = doodad->shape.color_ndx;
919        doodadWire.shape.shape_ndx = doodad->shape.shape_ndx;
920        break;
921    case XkbTextDoodad:
922        doodadWire.text.angle = doodad->text.angle;
923        doodadWire.text.width = doodad->text.width;
924        doodadWire.text.height = doodad->text.height;
925        doodadWire.text.color_ndx = doodad->text.color_ndx;
926        break;
927    case XkbIndicatorDoodad:
928        doodadWire.indicator.shape_ndx = doodad->indicator.shape_ndx;
929        doodadWire.indicator.on_color_ndx = doodad->indicator.on_color_ndx;
930        doodadWire.indicator.off_color_ndx = doodad->indicator.off_color_ndx;
931        break;
932    case XkbLogoDoodad:
933        doodadWire.logo.angle = doodad->logo.angle;
934        doodadWire.logo.color_ndx = doodad->logo.color_ndx;
935        doodadWire.logo.shape_ndx = doodad->logo.shape_ndx;
936        break;
937    default:
938        _XkbLibError(_XkbErrIllegalDoodad, "WriteXKMGeomDoodad",
939                     doodad->any.type);
940        return 0;
941    }
942    size += xkmPutCountedAtomString(dpy, file, doodad->any.name);
943    tmp = fwrite(&doodadWire, SIZEOF(xkmDoodadDesc), 1, file);
944    size += tmp * SIZEOF(xkmDoodadDesc);
945    if (doodad->any.type == XkbTextDoodad) {
946        size += xkmPutCountedString(file, doodad->text.text);
947        size += xkmPutCountedString(file, doodad->text.font);
948    }
949    else if (doodad->any.type == XkbLogoDoodad) {
950        size += xkmPutCountedString(file, doodad->logo.logo_name);
951    }
952    return size;
953}
954
955static unsigned
956WriteXKMGeomOverlay(FILE *file, XkbFileInfo *result, XkbOverlayPtr ol)
957{
958    register int r, k;
959    Display *dpy;
960    XkbDescPtr xkb;
961    XkbOverlayRowPtr row;
962    xkmOverlayDesc olWire;
963    xkmOverlayRowDesc rowWire;
964    xkmOverlayKeyDesc keyWire;
965    unsigned tmp, size = 0;
966
967    xkb = result->xkb;
968    dpy = xkb->dpy;
969    bzero((char *) &olWire, sizeof(olWire));
970    bzero((char *) &rowWire, sizeof(rowWire));
971    bzero((char *) &keyWire, sizeof(keyWire));
972    size += xkmPutCountedAtomString(dpy, file, ol->name);
973    olWire.num_rows = ol->num_rows;
974    tmp = fwrite(&olWire, SIZEOF(xkmOverlayDesc), 1, file);
975    size += tmp * SIZEOF(xkmOverlayDesc);
976    for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
977        XkbOverlayKeyPtr key;
978
979        rowWire.row_under = row->row_under;
980        rowWire.num_keys = row->num_keys;
981        tmp = fwrite(&rowWire, SIZEOF(xkmOverlayRowDesc), 1, file);
982        size += tmp * SIZEOF(xkmOverlayRowDesc);
983        for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
984            memcpy(keyWire.over, key->over.name, XkbKeyNameLength);
985            memcpy(keyWire.under, key->under.name, XkbKeyNameLength);
986            tmp = fwrite(&keyWire, SIZEOF(xkmOverlayKeyDesc), 1, file);
987            size += tmp * SIZEOF(xkmOverlayKeyDesc);
988        }
989    }
990    return size;
991}
992
993static unsigned
994WriteXKMGeomSection(FILE *file, XkbFileInfo *result, XkbSectionPtr section)
995{
996    register int i;
997    Display *dpy;
998    XkbDescPtr xkb;
999    xkmSectionDesc sectionWire;
1000    unsigned tmp, size = 0;
1001
1002    xkb = result->xkb;
1003    dpy = xkb->dpy;
1004    size += xkmPutCountedAtomString(dpy, file, section->name);
1005    sectionWire.top = section->top;
1006    sectionWire.left = section->left;
1007    sectionWire.width = section->width;
1008    sectionWire.height = section->height;
1009    sectionWire.angle = section->angle;
1010    sectionWire.priority = section->priority;
1011    sectionWire.num_rows = section->num_rows;
1012    sectionWire.num_doodads = section->num_doodads;
1013    sectionWire.num_overlays = section->num_overlays;
1014    tmp = fwrite(&sectionWire, SIZEOF(xkmSectionDesc), 1, file);
1015    size += tmp * SIZEOF(xkmSectionDesc);
1016    if (section->rows) {
1017        register unsigned k;
1018        XkbRowPtr row;
1019        xkmRowDesc rowWire;
1020        XkbKeyPtr key;
1021        xkmKeyDesc keyWire;
1022
1023        for (i = 0, row = section->rows; i < section->num_rows; i++, row++) {
1024            rowWire.top = row->top;
1025            rowWire.left = row->left;
1026            rowWire.num_keys = row->num_keys;
1027            rowWire.vertical = row->vertical;
1028            tmp = fwrite(&rowWire, SIZEOF(xkmRowDesc), 1, file);
1029            size += tmp * SIZEOF(xkmRowDesc);
1030            for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
1031                memcpy(keyWire.name, key->name.name, XkbKeyNameLength);
1032                keyWire.gap = key->gap;
1033                keyWire.shape_ndx = key->shape_ndx;
1034                keyWire.color_ndx = key->color_ndx;
1035                tmp = fwrite(&keyWire, SIZEOF(xkmKeyDesc), 1, file);
1036                size += tmp * SIZEOF(xkmKeyDesc);
1037            }
1038        }
1039    }
1040    if (section->doodads) {
1041        XkbDoodadPtr doodad;
1042
1043        for (i = 0, doodad = section->doodads; i < section->num_doodads;
1044             i++, doodad++) {
1045            size += WriteXKMGeomDoodad(file, result, doodad);
1046        }
1047    }
1048    if (section->overlays) {
1049        XkbOverlayPtr ol;
1050
1051        for (i = 0, ol = section->overlays; i < section->num_overlays;
1052             i++, ol++) {
1053            size += WriteXKMGeomOverlay(file, result, ol);
1054        }
1055    }
1056    return size;
1057}
1058
1059static unsigned
1060WriteXKMGeometry(FILE *file, XkbFileInfo *result)
1061{
1062    register int i;
1063    Display *dpy;
1064    XkbDescPtr xkb;
1065    XkbGeometryPtr geom;
1066    xkmGeometryDesc wire;
1067    unsigned tmp, size = 0;
1068
1069    xkb = result->xkb;
1070    if ((!xkb) || (!xkb->geom))
1071        return 0;
1072    dpy = xkb->dpy;
1073    geom = xkb->geom;
1074    wire.width_mm = geom->width_mm;
1075    wire.height_mm = geom->height_mm;
1076    wire.base_color_ndx = XkbGeomColorIndex(geom, geom->base_color);
1077    wire.label_color_ndx = XkbGeomColorIndex(geom, geom->label_color);
1078    wire.num_properties = geom->num_properties;
1079    wire.num_colors = geom->num_colors;
1080    wire.num_shapes = geom->num_shapes;
1081    wire.num_sections = geom->num_sections;
1082    wire.num_doodads = geom->num_doodads;
1083    wire.num_key_aliases = geom->num_key_aliases;
1084    size += xkmPutCountedAtomString(dpy, file, geom->name);
1085    tmp = fwrite(&wire, SIZEOF(xkmGeometryDesc), 1, file);
1086    size += tmp * SIZEOF(xkmGeometryDesc);
1087    size += xkmPutCountedString(file, geom->label_font);
1088    if (geom->properties) {
1089        XkbPropertyPtr prop;
1090
1091        for (i = 0, prop = geom->properties; i < geom->num_properties;
1092             i++, prop++) {
1093            size += xkmPutCountedString(file, prop->name);
1094            size += xkmPutCountedString(file, prop->value);
1095        }
1096    }
1097    if (geom->colors) {
1098        XkbColorPtr color;
1099
1100        for (i = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
1101            size += xkmPutCountedString(file, color->spec);
1102        }
1103    }
1104    if (geom->shapes) {
1105        XkbShapePtr shape;
1106        xkmShapeDesc shapeWire;
1107
1108        for (i = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
1109            register int n;
1110            XkbOutlinePtr ol;
1111            xkmOutlineDesc olWire;
1112
1113            bzero((char *) &shapeWire, sizeof(xkmShapeDesc));
1114            size += xkmPutCountedAtomString(dpy, file, shape->name);
1115            shapeWire.num_outlines = shape->num_outlines;
1116            if (shape->primary != NULL)
1117                shapeWire.primary_ndx = XkbOutlineIndex(shape, shape->primary);
1118            else
1119                shapeWire.primary_ndx = XkbNoShape;
1120            if (shape->approx != NULL)
1121                shapeWire.approx_ndx = XkbOutlineIndex(shape, shape->approx);
1122            else
1123                shapeWire.approx_ndx = XkbNoShape;
1124            tmp = fwrite(&shapeWire, SIZEOF(xkmShapeDesc), 1, file);
1125            size += tmp * SIZEOF(xkmShapeDesc);
1126            for (n = 0, ol = shape->outlines; n < shape->num_outlines;
1127                 n++, ol++) {
1128                register int p;
1129                XkbPointPtr pt;
1130                xkmPointDesc ptWire;
1131
1132                olWire.num_points = ol->num_points;
1133                olWire.corner_radius = ol->corner_radius;
1134                tmp = fwrite(&olWire, SIZEOF(xkmOutlineDesc), 1, file);
1135                size += tmp * SIZEOF(xkmOutlineDesc);
1136                for (p = 0, pt = ol->points; p < ol->num_points; p++, pt++) {
1137                    ptWire.x = pt->x;
1138                    ptWire.y = pt->y;
1139                    tmp = fwrite(&ptWire, SIZEOF(xkmPointDesc), 1, file);
1140                    size += tmp * SIZEOF(xkmPointDesc);
1141                }
1142            }
1143        }
1144    }
1145    if (geom->sections) {
1146        XkbSectionPtr section;
1147
1148        for (i = 0, section = geom->sections; i < geom->num_sections;
1149             i++, section++) {
1150            size += WriteXKMGeomSection(file, result, section);
1151        }
1152    }
1153    if (geom->doodads) {
1154        XkbDoodadPtr doodad;
1155
1156        for (i = 0, doodad = geom->doodads; i < geom->num_doodads;
1157             i++, doodad++) {
1158            size += WriteXKMGeomDoodad(file, result, doodad);
1159        }
1160    }
1161    if (geom->key_aliases) {
1162        tmp =
1163            fwrite(geom->key_aliases, 2 * XkbKeyNameLength,
1164                   geom->num_key_aliases, file);
1165        size += tmp * (2 * XkbKeyNameLength);
1166    }
1167    return size;
1168}
1169
1170/***====================================================================***/
1171
1172/*ARGSUSED*/
1173static int
1174GetXKMKeyNamesTOC(XkbFileInfo *result, XkmInfo *info,
1175                  int max_toc, xkmSectionInfo *toc_rtrn)
1176{
1177    int num_toc;
1178    int total_size;
1179
1180    total_size = num_toc = 0;
1181    if (SizeXKMKeycodes(result, &toc_rtrn[num_toc], &total_size))
1182        num_toc++;
1183    if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size))
1184        num_toc++;
1185    return num_toc;
1186}
1187
1188/*ARGSUSED*/
1189static int
1190GetXKMTypesTOC(XkbFileInfo *result, XkmInfo *info,
1191               int max_toc, xkmSectionInfo *toc_rtrn)
1192{
1193    int num_toc;
1194    int total_size;
1195
1196    total_size = num_toc = 0;
1197    if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size))
1198        num_toc++;
1199    if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size))
1200        num_toc++;
1201    return num_toc;
1202}
1203
1204/*ARGSUSED*/
1205static int
1206GetXKMCompatMapTOC(XkbFileInfo *result, XkmInfo *info,
1207                   int max_toc, xkmSectionInfo *toc_rtrn)
1208{
1209    int num_toc;
1210    int total_size;
1211
1212    total_size = num_toc = 0;
1213    if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size))
1214        num_toc++;
1215    if (SizeXKMCompatMap(result, info, &toc_rtrn[num_toc], &total_size))
1216        num_toc++;
1217    if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size))
1218        num_toc++;
1219    return num_toc;
1220}
1221
1222/*ARGSUSED*/
1223static int
1224GetXKMSemanticsTOC(XkbFileInfo *result, XkmInfo *info,
1225                   int max_toc, xkmSectionInfo *toc_rtrn)
1226{
1227    int num_toc;
1228    int total_size;
1229
1230    total_size = num_toc = 0;
1231    if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size))
1232        num_toc++;
1233    if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size))
1234        num_toc++;
1235    if (SizeXKMCompatMap(result, info, &toc_rtrn[num_toc], &total_size))
1236        num_toc++;
1237    if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size))
1238        num_toc++;
1239    return num_toc;
1240}
1241
1242/*ARGSUSED*/
1243static int
1244GetXKMLayoutTOC(XkbFileInfo *result, XkmInfo *info,
1245                int max_toc, xkmSectionInfo *toc_rtrn)
1246{
1247    int num_toc;
1248    int total_size;
1249
1250    total_size = num_toc = 0;
1251    if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size))
1252        num_toc++;
1253    if (SizeXKMKeycodes(result, &toc_rtrn[num_toc], &total_size))
1254        num_toc++;
1255    if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size))
1256        num_toc++;
1257    if (SizeXKMSymbols(result, info, &toc_rtrn[num_toc], &total_size))
1258        num_toc++;
1259    if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size))
1260        num_toc++;
1261    if (SizeXKMGeometry(result, &toc_rtrn[num_toc], &total_size))
1262        num_toc++;
1263    return num_toc;
1264}
1265
1266/*ARGSUSED*/
1267static int
1268GetXKMKeymapTOC(XkbFileInfo *result, XkmInfo *info,
1269                int max_toc, xkmSectionInfo *toc_rtrn)
1270{
1271    int num_toc;
1272    int total_size;
1273
1274    total_size = num_toc = 0;
1275    if (SizeXKMVirtualMods(result, info, &toc_rtrn[num_toc], &total_size))
1276        num_toc++;
1277    if (SizeXKMKeycodes(result, &toc_rtrn[num_toc], &total_size))
1278        num_toc++;
1279    if (SizeXKMKeyTypes(result, &toc_rtrn[num_toc], &total_size))
1280        num_toc++;
1281    if (SizeXKMCompatMap(result, info, &toc_rtrn[num_toc], &total_size))
1282        num_toc++;
1283    if (SizeXKMSymbols(result, info, &toc_rtrn[num_toc], &total_size))
1284        num_toc++;
1285    if (SizeXKMIndicators(result, info, &toc_rtrn[num_toc], &total_size))
1286        num_toc++;
1287    if (SizeXKMGeometry(result, &toc_rtrn[num_toc], &total_size))
1288        num_toc++;
1289    return num_toc;
1290}
1291
1292/*ARGSUSED*/
1293static int
1294GetXKMGeometryTOC(XkbFileInfo *result, XkmInfo *info,
1295                  int max_toc, xkmSectionInfo *toc_rtrn)
1296{
1297    int num_toc;
1298    int total_size;
1299
1300    total_size = num_toc = 0;
1301    if (SizeXKMGeometry(result, &toc_rtrn[num_toc], &total_size))
1302        num_toc++;
1303    return num_toc;
1304}
1305
1306static Bool
1307WriteXKMFile(FILE *file, XkbFileInfo *result,
1308             int num_toc, xkmSectionInfo *toc, XkmInfo *info)
1309{
1310    register int i;
1311    unsigned tmp, size, total = 0;
1312
1313    for (i = 0; i < num_toc; i++) {
1314        tmp = fwrite(&toc[i], SIZEOF(xkmSectionInfo), 1, file);
1315        total += tmp * SIZEOF(xkmSectionInfo);
1316        switch (toc[i].type) {
1317        case XkmTypesIndex:
1318            size = WriteXKMKeyTypes(file, result);
1319            break;
1320        case XkmCompatMapIndex:
1321            size = WriteXKMCompatMap(file, result, info);
1322            break;
1323        case XkmSymbolsIndex:
1324            size = WriteXKMSymbols(file, result, info);
1325            break;
1326        case XkmIndicatorsIndex:
1327            size = WriteXKMIndicators(file, result, info);
1328            break;
1329        case XkmKeyNamesIndex:
1330            size = WriteXKMKeycodes(file, result);
1331            break;
1332        case XkmGeometryIndex:
1333            size = WriteXKMGeometry(file, result);
1334            break;
1335        case XkmVirtualModsIndex:
1336            size = WriteXKMVirtualMods(file, result, info);
1337            break;
1338        default:
1339            _XkbLibError(_XkbErrIllegalTOCType, "WriteXKMFile", toc[i].type);
1340            return False;
1341        }
1342        size += SIZEOF(xkmSectionInfo);
1343        if (size != toc[i].size) {
1344            _XkbLibError(_XkbErrBadLength,
1345                         XkbConfigText(toc[i].type, XkbMessage),
1346                         size - toc[i].size);
1347            return False;
1348        }
1349    }
1350    return True;
1351}
1352
1353
1354#define	MAX_TOC	16
1355
1356Bool
1357XkbWriteXKMFile(FILE *out, XkbFileInfo *result)
1358{
1359    Bool ok;
1360    XkbDescPtr xkb;
1361    XkmInfo info;
1362    int size_toc, i;
1363    unsigned hdr, present;
1364    xkmFileInfo fileInfo;
1365    xkmSectionInfo toc[MAX_TOC];
1366
1367    int (*getTOC) (XkbFileInfo *        /* result */ ,
1368                   XkmInfo *            /* info */ ,
1369                   int                  /* max_to */ ,
1370                   xkmSectionInfo *     /* toc_rtrn */
1371        );
1372
1373    switch (result->type) {
1374    case XkmKeyNamesIndex:
1375        getTOC = GetXKMKeyNamesTOC;
1376        break;
1377    case XkmTypesIndex:
1378        getTOC = GetXKMTypesTOC;
1379        break;
1380    case XkmCompatMapIndex:
1381        getTOC = GetXKMCompatMapTOC;
1382        break;
1383    case XkmSemanticsFile:
1384        getTOC = GetXKMSemanticsTOC;
1385        break;
1386    case XkmLayoutFile:
1387        getTOC = GetXKMLayoutTOC;
1388        break;
1389    case XkmKeymapFile:
1390        getTOC = GetXKMKeymapTOC;
1391        break;
1392    case XkmGeometryFile:
1393    case XkmGeometryIndex:
1394        getTOC = GetXKMGeometryTOC;
1395        break;
1396    default:
1397        _XkbLibError(_XkbErrIllegalContents,
1398                     XkbConfigText(result->type, XkbMessage), 0);
1399        return False;
1400    }
1401    xkb = result->xkb;
1402
1403    bzero((char *) &info, sizeof(XkmInfo));
1404    size_toc = (*getTOC) (result, &info, MAX_TOC, toc);
1405    if (size_toc < 1) {
1406        _XkbLibError(_XkbErrEmptyFile, "XkbWriteXKMFile", 0);
1407        return False;
1408    }
1409    if (out == NULL) {
1410        _XkbLibError(_XkbErrFileCannotOpen, "XkbWriteXKMFile", 0);
1411        return False;
1412    }
1413    for (i = present = 0; i < size_toc; i++) {
1414        toc[i].offset += 4 + SIZEOF(xkmFileInfo);
1415        toc[i].offset += (size_toc * SIZEOF(xkmSectionInfo));
1416        if (toc[i].type <= XkmLastIndex) {
1417            present |= (1 << toc[i].type);
1418        }
1419#ifdef DEBUG
1420        else {
1421            fprintf(stderr, "Illegal section type %d\n", toc[i].type);
1422            fprintf(stderr, "Ignored\n");
1423        }
1424#endif
1425    }
1426    hdr = (('x' << 24) | ('k' << 16) | ('m' << 8) | XkmFileVersion);
1427    xkmPutCARD32(out, (unsigned long) hdr);
1428    fileInfo.type = result->type;
1429    fileInfo.min_kc = xkb->min_key_code;
1430    fileInfo.max_kc = xkb->max_key_code;
1431    fileInfo.num_toc = size_toc;
1432    fileInfo.present = present;
1433    fileInfo.pad = 0;
1434    fwrite(&fileInfo, SIZEOF(xkmFileInfo), 1, out);
1435    fwrite(toc, SIZEOF(xkmSectionInfo), size_toc, out);
1436    ok = WriteXKMFile(out, result, size_toc, toc, &info);
1437    return ok;
1438}
1439