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