1 /************************************************************
2 Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3 
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15 
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 
25 ********************************************************/
26 
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <X11/X.h>
33 #include <X11/Xproto.h>
34 #include "misc.h"
35 #include "inputstr.h"
36 #include <X11/keysym.h>
37 #define	XKBSRV_NEED_FILE_FUNCS
38 #include <xkbsrv.h>
39 
40 /***====================================================================***/
41 
42 Status
XkbAllocClientMap(XkbDescPtr xkb,unsigned which,unsigned nTotalTypes)43 XkbAllocClientMap(XkbDescPtr xkb, unsigned which, unsigned nTotalTypes)
44 {
45     register int i;
46     XkbClientMapPtr map;
47 
48     if ((xkb == NULL) ||
49         ((nTotalTypes > 0) && (nTotalTypes < XkbNumRequiredTypes)))
50         return BadValue;
51     if ((which & XkbKeySymsMask) &&
52         ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
53          (!XkbIsLegalKeycode(xkb->max_key_code)) ||
54          (xkb->max_key_code < xkb->min_key_code))) {
55         DebugF("bad keycode (%d,%d) in XkbAllocClientMap\n",
56                xkb->min_key_code, xkb->max_key_code);
57         return BadValue;
58     }
59 
60     if (xkb->map == NULL) {
61         map = calloc(1, sizeof(XkbClientMapRec));
62         if (map == NULL)
63             return BadAlloc;
64         xkb->map = map;
65     }
66     else
67         map = xkb->map;
68 
69     if ((which & XkbKeyTypesMask) && (nTotalTypes > 0)) {
70         if (map->types == NULL) {
71             map->types = calloc(nTotalTypes, sizeof(XkbKeyTypeRec));
72             if (map->types == NULL)
73                 return BadAlloc;
74             map->num_types = 0;
75             map->size_types = nTotalTypes;
76         }
77         else if (map->size_types < nTotalTypes) {
78             XkbKeyTypeRec *prev_types = map->types;
79 
80             map->types =
81                 reallocarray(map->types, nTotalTypes, sizeof(XkbKeyTypeRec));
82             if (map->types == NULL) {
83                 free(prev_types);
84                 map->num_types = map->size_types = 0;
85                 return BadAlloc;
86             }
87             map->size_types = nTotalTypes;
88             memset(&map->types[map->num_types], 0,
89                    ((map->size_types -
90                      map->num_types) * sizeof(XkbKeyTypeRec)));
91         }
92     }
93     if (which & XkbKeySymsMask) {
94         int nKeys = XkbNumKeys(xkb);
95 
96         if (map->syms == NULL) {
97             map->size_syms = (nKeys * 15) / 10;
98             map->syms = calloc(map->size_syms, sizeof(KeySym));
99             if (!map->syms) {
100                 map->size_syms = 0;
101                 return BadAlloc;
102             }
103             map->num_syms = 1;
104             map->syms[0] = NoSymbol;
105         }
106         if (map->key_sym_map == NULL) {
107             i = xkb->max_key_code + 1;
108             map->key_sym_map = calloc(i, sizeof(XkbSymMapRec));
109             if (map->key_sym_map == NULL)
110                 return BadAlloc;
111         }
112     }
113     if (which & XkbModifierMapMask) {
114         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
115             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
116             (xkb->max_key_code < xkb->min_key_code))
117             return BadMatch;
118         if (map->modmap == NULL) {
119             i = xkb->max_key_code + 1;
120             map->modmap = calloc(i, sizeof(unsigned char));
121             if (map->modmap == NULL)
122                 return BadAlloc;
123         }
124     }
125     return Success;
126 }
127 
128 Status
XkbAllocServerMap(XkbDescPtr xkb,unsigned which,unsigned nNewActions)129 XkbAllocServerMap(XkbDescPtr xkb, unsigned which, unsigned nNewActions)
130 {
131     register int i;
132     XkbServerMapPtr map;
133 
134     if (xkb == NULL)
135         return BadMatch;
136     if (xkb->server == NULL) {
137         map = calloc(1, sizeof(XkbServerMapRec));
138         if (map == NULL)
139             return BadAlloc;
140         for (i = 0; i < XkbNumVirtualMods; i++) {
141             map->vmods[i] = XkbNoModifierMask;
142         }
143         xkb->server = map;
144     }
145     else
146         map = xkb->server;
147     if (which & XkbExplicitComponentsMask) {
148         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
149             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
150             (xkb->max_key_code < xkb->min_key_code))
151             return BadMatch;
152         if (map->explicit == NULL) {
153             i = xkb->max_key_code + 1;
154             map->explicit = calloc(i, sizeof(unsigned char));
155             if (map->explicit == NULL)
156                 return BadAlloc;
157         }
158     }
159     if (which & XkbKeyActionsMask) {
160         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
161             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
162             (xkb->max_key_code < xkb->min_key_code))
163             return BadMatch;
164         if (nNewActions < 1)
165             nNewActions = 1;
166         if (map->acts == NULL) {
167             map->acts = calloc((nNewActions + 1), sizeof(XkbAction));
168             if (map->acts == NULL)
169                 return BadAlloc;
170             map->num_acts = 1;
171             map->size_acts = nNewActions + 1;
172         }
173         else if ((map->size_acts - map->num_acts) < nNewActions) {
174             unsigned need;
175             XkbAction *prev_acts = map->acts;
176 
177             need = map->num_acts + nNewActions;
178             map->acts = reallocarray(map->acts, need, sizeof(XkbAction));
179             if (map->acts == NULL) {
180                 free(prev_acts);
181                 map->num_acts = map->size_acts = 0;
182                 return BadAlloc;
183             }
184             map->size_acts = need;
185             memset(&map->acts[map->num_acts], 0,
186                    ((map->size_acts - map->num_acts) * sizeof(XkbAction)));
187         }
188         if (map->key_acts == NULL) {
189             i = xkb->max_key_code + 1;
190             map->key_acts = calloc(i, sizeof(unsigned short));
191             if (map->key_acts == NULL)
192                 return BadAlloc;
193         }
194     }
195     if (which & XkbKeyBehaviorsMask) {
196         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
197             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
198             (xkb->max_key_code < xkb->min_key_code))
199             return BadMatch;
200         if (map->behaviors == NULL) {
201             i = xkb->max_key_code + 1;
202             map->behaviors = calloc(i, sizeof(XkbBehavior));
203             if (map->behaviors == NULL)
204                 return BadAlloc;
205         }
206     }
207     if (which & XkbVirtualModMapMask) {
208         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
209             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
210             (xkb->max_key_code < xkb->min_key_code))
211             return BadMatch;
212         if (map->vmodmap == NULL) {
213             i = xkb->max_key_code + 1;
214             map->vmodmap = calloc(i, sizeof(unsigned short));
215             if (map->vmodmap == NULL)
216                 return BadAlloc;
217         }
218     }
219     return Success;
220 }
221 
222 /***====================================================================***/
223 
224 static Status
XkbCopyKeyType(XkbKeyTypePtr from,XkbKeyTypePtr into)225 XkbCopyKeyType(XkbKeyTypePtr from, XkbKeyTypePtr into)
226 {
227     if ((!from) || (!into))
228         return BadMatch;
229     free(into->map);
230     into->map = NULL;
231     free(into->preserve);
232     into->preserve = NULL;
233     free(into->level_names);
234     into->level_names = NULL;
235     *into = *from;
236     if ((from->map) && (into->map_count > 0)) {
237         into->map = calloc(into->map_count, sizeof(XkbKTMapEntryRec));
238         if (!into->map)
239             return BadAlloc;
240         memcpy(into->map, from->map,
241                into->map_count * sizeof(XkbKTMapEntryRec));
242     }
243     if ((from->preserve) && (into->map_count > 0)) {
244         into->preserve = calloc(into->map_count, sizeof(XkbModsRec));
245         if (!into->preserve)
246             return BadAlloc;
247         memcpy(into->preserve, from->preserve,
248                into->map_count * sizeof(XkbModsRec));
249     }
250     if ((from->level_names) && (into->num_levels > 0)) {
251         into->level_names = calloc(into->num_levels, sizeof(Atom));
252         if (!into->level_names)
253             return BadAlloc;
254         memcpy(into->level_names, from->level_names,
255                into->num_levels * sizeof(Atom));
256     }
257     return Success;
258 }
259 
260 Status
XkbCopyKeyTypes(XkbKeyTypePtr from,XkbKeyTypePtr into,int num_types)261 XkbCopyKeyTypes(XkbKeyTypePtr from, XkbKeyTypePtr into, int num_types)
262 {
263     register int i, rtrn;
264 
265     if ((!from) || (!into) || (num_types < 0))
266         return BadMatch;
267     for (i = 0; i < num_types; i++) {
268         if ((rtrn = XkbCopyKeyType(from++, into++)) != Success)
269             return rtrn;
270     }
271     return Success;
272 }
273 
274 Status
XkbResizeKeyType(XkbDescPtr xkb,int type_ndx,int map_count,Bool want_preserve,int new_num_lvls)275 XkbResizeKeyType(XkbDescPtr xkb,
276                  int type_ndx,
277                  int map_count, Bool want_preserve, int new_num_lvls)
278 {
279     XkbKeyTypePtr type;
280     KeyCode matchingKeys[XkbMaxKeyCount], nMatchingKeys;
281 
282     if ((type_ndx < 0) || (type_ndx >= xkb->map->num_types) || (map_count < 0)
283         || (new_num_lvls < 1))
284         return BadValue;
285     switch (type_ndx) {
286     case XkbOneLevelIndex:
287         if (new_num_lvls != 1)
288             return BadMatch;
289         break;
290     case XkbTwoLevelIndex:
291     case XkbAlphabeticIndex:
292     case XkbKeypadIndex:
293         if (new_num_lvls != 2)
294             return BadMatch;
295         break;
296     }
297     type = &xkb->map->types[type_ndx];
298     if (map_count == 0) {
299         free(type->map);
300         type->map = NULL;
301         free(type->preserve);
302         type->preserve = NULL;
303         type->map_count = 0;
304     }
305     else {
306         XkbKTMapEntryRec *prev_map = type->map;
307 
308         if ((map_count > type->map_count) || (type->map == NULL))
309             type->map =
310                 reallocarray(type->map, map_count, sizeof(XkbKTMapEntryRec));
311         if (!type->map) {
312             free(prev_map);
313             return BadAlloc;
314         }
315         if (want_preserve) {
316             XkbModsRec *prev_preserve = type->preserve;
317 
318             if ((map_count > type->map_count) || (type->preserve == NULL)) {
319                 type->preserve = reallocarray(type->preserve,
320                                               map_count, sizeof(XkbModsRec));
321             }
322             if (!type->preserve) {
323                 free(prev_preserve);
324                 return BadAlloc;
325             }
326         }
327         else {
328             free(type->preserve);
329             type->preserve = NULL;
330         }
331         type->map_count = map_count;
332     }
333 
334     if ((new_num_lvls > type->num_levels) || (type->level_names == NULL)) {
335         Atom *prev_level_names = type->level_names;
336 
337         type->level_names = reallocarray(type->level_names,
338                                          new_num_lvls, sizeof(Atom));
339         if (!type->level_names) {
340             free(prev_level_names);
341             return BadAlloc;
342         }
343     }
344     /*
345      * Here's the theory:
346      *    If the width of the type changed, we might have to resize the symbol
347      * maps for any keys that use the type for one or more groups.  This is
348      * expensive, so we'll try to cull out any keys that are obviously okay:
349      * In any case:
350      *    - keys that have a group width <= the old width are okay (because
351      *      they could not possibly have been associated with the old type)
352      * If the key type increased in size:
353      *    - keys that already have a group width >= to the new width are okay
354      *    + keys that have a group width >= the old width but < the new width
355      *      might have to be enlarged.
356      * If the key type decreased in size:
357      *    - keys that have a group width > the old width don't have to be
358      *      resized (because they must have some other wider type associated
359      *      with some group).
360      *    + keys that have a group width == the old width might have to be
361      *      shrunk.
362      * The possibilities marked with '+' require us to examine the key types
363      * associated with each group for the key.
364      */
365     memset(matchingKeys, 0, XkbMaxKeyCount * sizeof(KeyCode));
366     nMatchingKeys = 0;
367     if (new_num_lvls > type->num_levels) {
368         int nTotal;
369         KeySym *newSyms;
370         int width, match, nResize;
371         register int i, g, nSyms;
372 
373         nResize = 0;
374         for (nTotal = 1, i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
375             width = XkbKeyGroupsWidth(xkb, i);
376             if (width < type->num_levels || width >= new_num_lvls) {
377                 nTotal += XkbKeyNumSyms(xkb,i);
378                 continue;
379             }
380             for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
381                  (g >= 0) && (!match); g--) {
382                 if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
383                     matchingKeys[nMatchingKeys++] = i;
384                     match = 1;
385                 }
386             }
387             if (!match)
388                 nTotal += XkbKeyNumSyms(xkb, i);
389             else {
390                 nTotal += XkbKeyNumGroups(xkb, i) * new_num_lvls;
391                 nResize++;
392             }
393         }
394         if (nResize > 0) {
395             int nextMatch;
396 
397             xkb->map->size_syms = (nTotal * 15) / 10;
398             newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
399             if (newSyms == NULL)
400                 return BadAlloc;
401             nextMatch = 0;
402             nSyms = 1;
403             for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
404                 if (matchingKeys[nextMatch] == i) {
405                     KeySym *pOld;
406 
407                     nextMatch++;
408                     width = XkbKeyGroupsWidth(xkb, i);
409                     pOld = XkbKeySymsPtr(xkb, i);
410                     for (g = XkbKeyNumGroups(xkb, i) - 1; g >= 0; g--) {
411                         memcpy(&newSyms[nSyms + (new_num_lvls * g)],
412                                &pOld[width * g], width * sizeof(KeySym));
413                     }
414                     xkb->map->key_sym_map[i].offset = nSyms;
415                     nSyms += XkbKeyNumGroups(xkb, i) * new_num_lvls;
416                 }
417                 else {
418                     memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
419                            XkbKeyNumSyms(xkb, i) * sizeof(KeySym));
420                     xkb->map->key_sym_map[i].offset = nSyms;
421                     nSyms += XkbKeyNumSyms(xkb, i);
422                 }
423             }
424             type->num_levels = new_num_lvls;
425             free(xkb->map->syms);
426             xkb->map->syms = newSyms;
427             xkb->map->num_syms = nSyms;
428             return Success;
429         }
430     }
431     else if (new_num_lvls < type->num_levels) {
432         int width, match;
433         register int g, i;
434 
435         for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
436             width = XkbKeyGroupsWidth(xkb, i);
437             if (width < type->num_levels)
438                 continue;
439             for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
440                  (g >= 0) && (!match); g--) {
441                 if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
442                     matchingKeys[nMatchingKeys++] = i;
443                     match = 1;
444                 }
445             }
446         }
447     }
448     if (nMatchingKeys > 0) {
449         int key, firstClear;
450         register int i, g;
451 
452         if (new_num_lvls > type->num_levels)
453             firstClear = type->num_levels;
454         else
455             firstClear = new_num_lvls;
456         for (i = 0; i < nMatchingKeys; i++) {
457             KeySym *pSyms;
458             int width, nClear;
459 
460             key = matchingKeys[i];
461             width = XkbKeyGroupsWidth(xkb, key);
462             nClear = width - firstClear;
463             pSyms = XkbKeySymsPtr(xkb, key);
464             for (g = XkbKeyNumGroups(xkb, key) - 1; g >= 0; g--) {
465                 if (XkbKeyKeyTypeIndex(xkb, key, g) == type_ndx) {
466                     if (nClear > 0)
467                         memset(&pSyms[g * width + firstClear], 0,
468                                nClear * sizeof(KeySym));
469                 }
470             }
471         }
472     }
473     type->num_levels = new_num_lvls;
474     return Success;
475 }
476 
477 KeySym *
XkbResizeKeySyms(XkbDescPtr xkb,int key,int needed)478 XkbResizeKeySyms(XkbDescPtr xkb, int key, int needed)
479 {
480     register int i, nSyms, nKeySyms;
481     unsigned nOldSyms;
482     KeySym *newSyms;
483 
484     if (needed == 0) {
485         xkb->map->key_sym_map[key].offset = 0;
486         return xkb->map->syms;
487     }
488     nOldSyms = XkbKeyNumSyms(xkb, key);
489     if (nOldSyms >= (unsigned) needed) {
490         return XkbKeySymsPtr(xkb, key);
491     }
492     if (xkb->map->size_syms - xkb->map->num_syms >= (unsigned) needed) {
493         if (nOldSyms > 0) {
494             memcpy(&xkb->map->syms[xkb->map->num_syms], XkbKeySymsPtr(xkb, key),
495                    nOldSyms * sizeof(KeySym));
496         }
497         if ((needed - nOldSyms) > 0) {
498             memset(&xkb->map->
499                    syms[xkb->map->num_syms + XkbKeyNumSyms(xkb, key)], 0,
500                    (needed - nOldSyms) * sizeof(KeySym));
501         }
502         xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
503         xkb->map->num_syms += needed;
504         return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
505     }
506     xkb->map->size_syms += (needed > 32 ? needed : 32);
507     newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
508     if (newSyms == NULL)
509         return NULL;
510     newSyms[0] = NoSymbol;
511     nSyms = 1;
512     for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
513         int nCopy;
514 
515         nCopy = nKeySyms = XkbKeyNumSyms(xkb, i);
516         if ((nKeySyms == 0) && (i != key))
517             continue;
518         if (i == key)
519             nKeySyms = needed;
520         if (nCopy != 0)
521             memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
522                    nCopy * sizeof(KeySym));
523         if (nKeySyms > nCopy)
524             memset(&newSyms[nSyms + nCopy], 0,
525                    (nKeySyms - nCopy) * sizeof(KeySym));
526         xkb->map->key_sym_map[i].offset = nSyms;
527         nSyms += nKeySyms;
528     }
529     free(xkb->map->syms);
530     xkb->map->syms = newSyms;
531     xkb->map->num_syms = nSyms;
532     return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
533 }
534 
535 static unsigned
_ExtendRange(unsigned int old_flags,unsigned int flag,KeyCode newKC,KeyCode * old_min,unsigned char * old_num)536 _ExtendRange(unsigned int old_flags,
537              unsigned int flag,
538              KeyCode newKC, KeyCode *old_min, unsigned char *old_num)
539 {
540     if ((old_flags & flag) == 0) {
541         old_flags |= flag;
542         *old_min = newKC;
543         *old_num = 1;
544     }
545     else {
546         int last = (*old_min) + (*old_num) - 1;
547 
548         if (newKC < *old_min) {
549             *old_min = newKC;
550             *old_num = (last - newKC) + 1;
551         }
552         else if (newKC > last) {
553             *old_num = (newKC - (*old_min)) + 1;
554         }
555     }
556     return old_flags;
557 }
558 
559 Status
XkbChangeKeycodeRange(XkbDescPtr xkb,int minKC,int maxKC,XkbChangesPtr changes)560 XkbChangeKeycodeRange(XkbDescPtr xkb,
561                       int minKC, int maxKC, XkbChangesPtr changes)
562 {
563     int tmp;
564 
565     if ((!xkb) || (minKC < XkbMinLegalKeyCode) || (maxKC > XkbMaxLegalKeyCode))
566         return BadValue;
567     if (minKC > maxKC)
568         return BadMatch;
569     if (minKC < xkb->min_key_code) {
570         if (changes)
571             changes->map.min_key_code = minKC;
572         tmp = xkb->min_key_code - minKC;
573         if (xkb->map) {
574             if (xkb->map->key_sym_map) {
575                 memset((char *) &xkb->map->key_sym_map[minKC], 0,
576                        tmp * sizeof(XkbSymMapRec));
577                 if (changes) {
578                     changes->map.changed = _ExtendRange(changes->map.changed,
579                                                         XkbKeySymsMask, minKC,
580                                                         &changes->map.
581                                                         first_key_sym,
582                                                         &changes->map.
583                                                         num_key_syms);
584                 }
585             }
586             if (xkb->map->modmap) {
587                 memset((char *) &xkb->map->modmap[minKC], 0, tmp);
588                 if (changes) {
589                     changes->map.changed = _ExtendRange(changes->map.changed,
590                                                         XkbModifierMapMask,
591                                                         minKC,
592                                                         &changes->map.
593                                                         first_modmap_key,
594                                                         &changes->map.
595                                                         num_modmap_keys);
596                 }
597             }
598         }
599         if (xkb->server) {
600             if (xkb->server->behaviors) {
601                 memset((char *) &xkb->server->behaviors[minKC], 0,
602                        tmp * sizeof(XkbBehavior));
603                 if (changes) {
604                     changes->map.changed = _ExtendRange(changes->map.changed,
605                                                         XkbKeyBehaviorsMask,
606                                                         minKC,
607                                                         &changes->map.
608                                                         first_key_behavior,
609                                                         &changes->map.
610                                                         num_key_behaviors);
611                 }
612             }
613             if (xkb->server->key_acts) {
614                 memset((char *) &xkb->server->key_acts[minKC], 0,
615                        tmp * sizeof(unsigned short));
616                 if (changes) {
617                     changes->map.changed = _ExtendRange(changes->map.changed,
618                                                         XkbKeyActionsMask,
619                                                         minKC,
620                                                         &changes->map.
621                                                         first_key_act,
622                                                         &changes->map.
623                                                         num_key_acts);
624                 }
625             }
626             if (xkb->server->vmodmap) {
627                 memset((char *) &xkb->server->vmodmap[minKC], 0,
628                        tmp * sizeof(unsigned short));
629                 if (changes) {
630                     changes->map.changed = _ExtendRange(changes->map.changed,
631                                                         XkbVirtualModMapMask,
632                                                         minKC,
633                                                         &changes->map.
634                                                         first_modmap_key,
635                                                         &changes->map.
636                                                         num_vmodmap_keys);
637                 }
638             }
639         }
640         if ((xkb->names) && (xkb->names->keys)) {
641             memset((char *) &xkb->names->keys[minKC], 0,
642                    tmp * sizeof(XkbKeyNameRec));
643             if (changes) {
644                 changes->names.changed = _ExtendRange(changes->names.changed,
645                                                       XkbKeyNamesMask, minKC,
646                                                       &changes->names.first_key,
647                                                       &changes->names.num_keys);
648             }
649         }
650         xkb->min_key_code = minKC;
651     }
652     if (maxKC > xkb->max_key_code) {
653         if (changes)
654             changes->map.max_key_code = maxKC;
655         tmp = maxKC - xkb->max_key_code;
656         if (xkb->map) {
657             if (xkb->map->key_sym_map) {
658                 XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
659 
660                 xkb->map->key_sym_map = reallocarray(xkb->map->key_sym_map,
661                                                      maxKC + 1,
662                                                      sizeof(XkbSymMapRec));
663                 if (!xkb->map->key_sym_map) {
664                     free(prev_key_sym_map);
665                     return BadAlloc;
666                 }
667                 memset((char *) &xkb->map->key_sym_map[xkb->max_key_code], 0,
668                        tmp * sizeof(XkbSymMapRec));
669                 if (changes) {
670                     changes->map.changed = _ExtendRange(changes->map.changed,
671                                                         XkbKeySymsMask, maxKC,
672                                                         &changes->map.
673                                                         first_key_sym,
674                                                         &changes->map.
675                                                         num_key_syms);
676                 }
677             }
678             if (xkb->map->modmap) {
679                 unsigned char *prev_modmap = xkb->map->modmap;
680 
681                 xkb->map->modmap = reallocarray(xkb->map->modmap,
682                                                 maxKC + 1,
683                                                 sizeof(unsigned char));
684                 if (!xkb->map->modmap) {
685                     free(prev_modmap);
686                     return BadAlloc;
687                 }
688                 memset((char *) &xkb->map->modmap[xkb->max_key_code], 0, tmp);
689                 if (changes) {
690                     changes->map.changed = _ExtendRange(changes->map.changed,
691                                                         XkbModifierMapMask,
692                                                         maxKC,
693                                                         &changes->map.
694                                                         first_modmap_key,
695                                                         &changes->map.
696                                                         num_modmap_keys);
697                 }
698             }
699         }
700         if (xkb->server) {
701             if (xkb->server->behaviors) {
702                 XkbBehavior *prev_behaviors = xkb->server->behaviors;
703 
704                 xkb->server->behaviors = reallocarray(xkb->server->behaviors,
705                                                       maxKC + 1,
706                                                       sizeof(XkbBehavior));
707                 if (!xkb->server->behaviors) {
708                     free(prev_behaviors);
709                     return BadAlloc;
710                 }
711                 memset((char *) &xkb->server->behaviors[xkb->max_key_code], 0,
712                        tmp * sizeof(XkbBehavior));
713                 if (changes) {
714                     changes->map.changed = _ExtendRange(changes->map.changed,
715                                                         XkbKeyBehaviorsMask,
716                                                         maxKC,
717                                                         &changes->map.
718                                                         first_key_behavior,
719                                                         &changes->map.
720                                                         num_key_behaviors);
721                 }
722             }
723             if (xkb->server->key_acts) {
724                 unsigned short *prev_key_acts = xkb->server->key_acts;
725 
726                 xkb->server->key_acts = reallocarray(xkb->server->key_acts,
727                                                      maxKC + 1,
728                                                      sizeof(unsigned short));
729                 if (!xkb->server->key_acts) {
730                     free(prev_key_acts);
731                     return BadAlloc;
732                 }
733                 memset((char *) &xkb->server->key_acts[xkb->max_key_code], 0,
734                        tmp * sizeof(unsigned short));
735                 if (changes) {
736                     changes->map.changed = _ExtendRange(changes->map.changed,
737                                                         XkbKeyActionsMask,
738                                                         maxKC,
739                                                         &changes->map.
740                                                         first_key_act,
741                                                         &changes->map.
742                                                         num_key_acts);
743                 }
744             }
745             if (xkb->server->vmodmap) {
746                 unsigned short *prev_vmodmap = xkb->server->vmodmap;
747 
748                 xkb->server->vmodmap = reallocarray(xkb->server->vmodmap,
749                                                     maxKC + 1,
750                                                     sizeof(unsigned short));
751                 if (!xkb->server->vmodmap) {
752                     free(prev_vmodmap);
753                     return BadAlloc;
754                 }
755                 memset((char *) &xkb->server->vmodmap[xkb->max_key_code], 0,
756                        tmp * sizeof(unsigned short));
757                 if (changes) {
758                     changes->map.changed = _ExtendRange(changes->map.changed,
759                                                         XkbVirtualModMapMask,
760                                                         maxKC,
761                                                         &changes->map.
762                                                         first_modmap_key,
763                                                         &changes->map.
764                                                         num_vmodmap_keys);
765                 }
766             }
767         }
768         if ((xkb->names) && (xkb->names->keys)) {
769             XkbKeyNameRec *prev_keys = xkb->names->keys;
770 
771             xkb->names->keys = reallocarray(xkb->names->keys,
772                                             maxKC + 1, sizeof(XkbKeyNameRec));
773             if (!xkb->names->keys) {
774                 free(prev_keys);
775                 return BadAlloc;
776             }
777             memset((char *) &xkb->names->keys[xkb->max_key_code], 0,
778                    tmp * sizeof(XkbKeyNameRec));
779             if (changes) {
780                 changes->names.changed = _ExtendRange(changes->names.changed,
781                                                       XkbKeyNamesMask, maxKC,
782                                                       &changes->names.first_key,
783                                                       &changes->names.num_keys);
784             }
785         }
786         xkb->max_key_code = maxKC;
787     }
788     return Success;
789 }
790 
791 XkbAction *
XkbResizeKeyActions(XkbDescPtr xkb,int key,int needed)792 XkbResizeKeyActions(XkbDescPtr xkb, int key, int needed)
793 {
794     register int i, nActs;
795     XkbAction *newActs;
796 
797     if (needed == 0) {
798         xkb->server->key_acts[key] = 0;
799         return NULL;
800     }
801     if (XkbKeyHasActions(xkb, key) &&
802         (XkbKeyNumSyms(xkb, key) >= (unsigned) needed))
803         return XkbKeyActionsPtr(xkb, key);
804     if (xkb->server->size_acts - xkb->server->num_acts >= (unsigned) needed) {
805         xkb->server->key_acts[key] = xkb->server->num_acts;
806         xkb->server->num_acts += needed;
807         return &xkb->server->acts[xkb->server->key_acts[key]];
808     }
809     xkb->server->size_acts = xkb->server->num_acts + needed + 8;
810     newActs = calloc(xkb->server->size_acts, sizeof(XkbAction));
811     if (newActs == NULL)
812         return NULL;
813     newActs[0].type = XkbSA_NoAction;
814     nActs = 1;
815     for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
816         int nKeyActs, nCopy;
817 
818         if ((xkb->server->key_acts[i] == 0) && (i != key))
819             continue;
820 
821         nCopy = nKeyActs = XkbKeyNumActions(xkb, i);
822         if (i == key) {
823             nKeyActs = needed;
824             if (needed < nCopy)
825                 nCopy = needed;
826         }
827 
828         if (nCopy > 0)
829             memcpy(&newActs[nActs], XkbKeyActionsPtr(xkb, i),
830                    nCopy * sizeof(XkbAction));
831         if (nCopy < nKeyActs)
832             memset(&newActs[nActs + nCopy], 0,
833                    (nKeyActs - nCopy) * sizeof(XkbAction));
834         xkb->server->key_acts[i] = nActs;
835         nActs += nKeyActs;
836     }
837     free(xkb->server->acts);
838     xkb->server->acts = newActs;
839     xkb->server->num_acts = nActs;
840     return &xkb->server->acts[xkb->server->key_acts[key]];
841 }
842 
843 void
XkbFreeClientMap(XkbDescPtr xkb,unsigned what,Bool freeMap)844 XkbFreeClientMap(XkbDescPtr xkb, unsigned what, Bool freeMap)
845 {
846     XkbClientMapPtr map;
847 
848     if ((xkb == NULL) || (xkb->map == NULL))
849         return;
850     if (freeMap)
851         what = XkbAllClientInfoMask;
852     map = xkb->map;
853     if (what & XkbKeyTypesMask) {
854         if (map->types != NULL) {
855             if (map->num_types > 0) {
856                 register int i;
857                 XkbKeyTypePtr type;
858 
859                 for (i = 0, type = map->types; i < map->num_types; i++, type++) {
860                     free(type->map);
861                     type->map = NULL;
862                     free(type->preserve);
863                     type->preserve = NULL;
864                     type->map_count = 0;
865                     free(type->level_names);
866                     type->level_names = NULL;
867                 }
868             }
869             free(map->types);
870             map->num_types = map->size_types = 0;
871             map->types = NULL;
872         }
873     }
874     if (what & XkbKeySymsMask) {
875         free(map->key_sym_map);
876         map->key_sym_map = NULL;
877         if (map->syms != NULL) {
878             free(map->syms);
879             map->size_syms = map->num_syms = 0;
880             map->syms = NULL;
881         }
882     }
883     if ((what & XkbModifierMapMask) && (map->modmap != NULL)) {
884         free(map->modmap);
885         map->modmap = NULL;
886     }
887     if (freeMap) {
888         free(xkb->map);
889         xkb->map = NULL;
890     }
891     return;
892 }
893 
894 void
XkbFreeServerMap(XkbDescPtr xkb,unsigned what,Bool freeMap)895 XkbFreeServerMap(XkbDescPtr xkb, unsigned what, Bool freeMap)
896 {
897     XkbServerMapPtr map;
898 
899     if ((xkb == NULL) || (xkb->server == NULL))
900         return;
901     if (freeMap)
902         what = XkbAllServerInfoMask;
903     map = xkb->server;
904     if ((what & XkbExplicitComponentsMask) && (map->explicit != NULL)) {
905         free(map->explicit);
906         map->explicit = NULL;
907     }
908     if (what & XkbKeyActionsMask) {
909         free(map->key_acts);
910         map->key_acts = NULL;
911         if (map->acts != NULL) {
912             free(map->acts);
913             map->num_acts = map->size_acts = 0;
914             map->acts = NULL;
915         }
916     }
917     if ((what & XkbKeyBehaviorsMask) && (map->behaviors != NULL)) {
918         free(map->behaviors);
919         map->behaviors = NULL;
920     }
921     if ((what & XkbVirtualModMapMask) && (map->vmodmap != NULL)) {
922         free(map->vmodmap);
923         map->vmodmap = NULL;
924     }
925 
926     if (freeMap) {
927         free(xkb->server);
928         xkb->server = NULL;
929     }
930     return;
931 }
932