1/************************************************************
2Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#define	NEED_MAP_READERS
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "Xlibint.h"
32#include <X11/extensions/XKBproto.h>
33#include "XKBlibint.h"
34
35/***====================================================================***/
36
37static void
38_FreeComponentNames(int num, XkbComponentNamePtr names)
39{
40    int i;
41    XkbComponentNamePtr tmp;
42
43    if ((num < 1) || (names == NULL))
44        return;
45    for (i = 0, tmp = names; i < num; i++, tmp++) {
46        if (tmp->name) {
47            _XkbFree(tmp->name);
48            tmp->name = NULL;
49        }
50    }
51    _XkbFree(names);
52    return;
53}
54
55/***====================================================================***/
56
57static XkbComponentNamePtr
58_ReadListing(XkbReadBufferPtr buf, int count, Status * status_rtrn)
59{
60    XkbComponentNamePtr first, this;
61    register int i;
62    CARD16 *flags;
63    int slen, wlen;
64    char *str;
65
66    if (count < 1)
67        return NULL;
68    first = _XkbTypedCalloc(count, XkbComponentNameRec);
69    if (!first)
70        return NULL;
71    for (this = first, i = 0; i < count; i++, this++) {
72        flags = (CARD16 *) _XkbGetReadBufferPtr(buf, 2 * sizeof(CARD16));
73        if (!flags)
74            goto BAILOUT;
75        this->flags = flags[0];
76        slen = flags[1];
77        wlen = ((slen + 1) / 2) * 2;    /* pad to 2 byte boundary */
78        this->name = _XkbTypedCalloc(slen + 1, char);
79
80        if (!this->name)
81            goto BAILOUT;
82        str = (char *) _XkbGetReadBufferPtr(buf, wlen);
83        if (!str)
84            goto BAILOUT;
85        memcpy(this->name, str, (size_t) slen);
86    }
87    return first;
88 BAILOUT:
89    *status_rtrn = BadAlloc;
90    _FreeComponentNames(i, first);
91    return NULL;
92}
93
94/***====================================================================***/
95
96XkbComponentListPtr
97XkbListComponents(Display *dpy,
98                  unsigned deviceSpec,
99                  XkbComponentNamesPtr ptrns,
100                  int *max_inout)
101{
102    register xkbListComponentsReq *req;
103    xkbListComponentsReply rep;
104    XkbInfoPtr xkbi;
105    XkbComponentListPtr list;
106    XkbReadBufferRec buf;
107    int left;
108    char *str;
109    int extraLen, len, mapLen, codesLen, typesLen, compatLen, symsLen, geomLen;
110
111    if ((dpy == NULL) || (dpy->flags & XlibDisplayNoXkb) ||
112        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
113        (ptrns == NULL) || (max_inout == NULL))
114        return NULL;
115
116    xkbi = dpy->xkb_info;
117    LockDisplay(dpy);
118    GetReq(kbListComponents, req);
119    req->reqType = xkbi->codes->major_opcode;
120    req->xkbReqType = X_kbListComponents;
121    req->deviceSpec = deviceSpec;
122    req->maxNames = *max_inout;
123
124    mapLen = codesLen = typesLen = compatLen = symsLen = geomLen = 0;
125    if (ptrns->keymap)
126        mapLen = (int) strlen(ptrns->keymap);
127    if (ptrns->keycodes)
128        codesLen = (int) strlen(ptrns->keycodes);
129    if (ptrns->types)
130        typesLen = (int) strlen(ptrns->types);
131    if (ptrns->compat)
132        compatLen = (int) strlen(ptrns->compat);
133    if (ptrns->symbols)
134        symsLen = (int) strlen(ptrns->symbols);
135    if (ptrns->geometry)
136        geomLen = (int) strlen(ptrns->geometry);
137    if (mapLen > 255)
138        mapLen = 255;
139    if (codesLen > 255)
140        codesLen = 255;
141    if (typesLen > 255)
142        typesLen = 255;
143    if (compatLen > 255)
144        compatLen = 255;
145    if (symsLen > 255)
146        symsLen = 255;
147    if (geomLen > 255)
148        geomLen = 255;
149
150    len = mapLen + codesLen + typesLen + compatLen + symsLen + geomLen + 6;
151    len = XkbPaddedSize(len);
152    req->length += len / 4;
153    BufAlloc(char *, str, len);
154
155    *str++ = mapLen;
156    if (mapLen > 0) {
157        memcpy(str, ptrns->keymap, (size_t) mapLen);
158        str += mapLen;
159    }
160    *str++ = codesLen;
161    if (codesLen > 0) {
162        memcpy(str, ptrns->keycodes, (size_t) codesLen);
163        str += codesLen;
164    }
165    *str++ = typesLen;
166    if (typesLen > 0) {
167        memcpy(str, ptrns->types, (size_t) typesLen);
168        str += typesLen;
169    }
170    *str++ = compatLen;
171    if (compatLen > 0) {
172        memcpy(str, ptrns->compat, (size_t) compatLen);
173        str += compatLen;
174    }
175    *str++ = symsLen;
176    if (symsLen > 0) {
177        memcpy(str, ptrns->symbols, (size_t) symsLen);
178        str += symsLen;
179    }
180    *str++ = geomLen;
181    if (geomLen > 0) {
182        memcpy(str, ptrns->geometry, (size_t) geomLen);
183        str += geomLen;
184    }
185    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse))
186        goto BAILOUT;
187    extraLen = (int) rep.length * 4;
188    *max_inout = rep.extra;
189    if (extraLen == 0) {        /* no matches, but we don't want to report a failure */
190        list = _XkbTypedCalloc(1, XkbComponentListRec);
191        UnlockDisplay(dpy);
192        SyncHandle();
193        return list;
194    }
195    if (_XkbInitReadBuffer(dpy, &buf, extraLen)) {
196        Status status = Success;
197
198        list = _XkbTypedCalloc(1, XkbComponentListRec);
199        if (!list) {
200            _XkbFreeReadBuffer(&buf);
201            goto BAILOUT;
202        }
203        list->num_keymaps = rep.nKeymaps;
204        list->num_keycodes = rep.nKeycodes;
205        list->num_types = rep.nTypes;
206        list->num_compat = rep.nCompatMaps;
207        list->num_symbols = rep.nSymbols;
208        list->num_geometry = rep.nGeometries;
209        if ((status == Success) && (list->num_keymaps > 0))
210            list->keymaps = _ReadListing(&buf, list->num_keymaps, &status);
211        if ((status == Success) && (list->num_keycodes > 0))
212            list->keycodes = _ReadListing(&buf, list->num_keycodes, &status);
213        if ((status == Success) && (list->num_types > 0))
214            list->types = _ReadListing(&buf, list->num_types, &status);
215        if ((status == Success) && (list->num_compat > 0))
216            list->compat = _ReadListing(&buf, list->num_compat, &status);
217        if ((status == Success) && (list->num_symbols > 0))
218            list->symbols = _ReadListing(&buf, list->num_symbols, &status);
219        if ((status == Success) && (list->num_geometry > 0))
220            list->geometry = _ReadListing(&buf, list->num_geometry, &status);
221        left = _XkbFreeReadBuffer(&buf);
222        if ((status != Success) || (buf.error) || (left > 2)) {
223            XkbFreeComponentList(list);
224            goto BAILOUT;
225        }
226        UnlockDisplay(dpy);
227        SyncHandle();
228        return list;
229    }
230 BAILOUT:
231    UnlockDisplay(dpy);
232    SyncHandle();
233    return NULL;
234}
235
236void
237XkbFreeComponentList(XkbComponentListPtr list)
238{
239    if (list) {
240        if (list->keymaps)
241            _FreeComponentNames(list->num_keymaps, list->keymaps);
242        if (list->keycodes)
243            _FreeComponentNames(list->num_keycodes, list->keycodes);
244        if (list->types)
245            _FreeComponentNames(list->num_types, list->types);
246        if (list->compat)
247            _FreeComponentNames(list->num_compat, list->compat);
248        if (list->symbols)
249            _FreeComponentNames(list->num_symbols, list->symbols);
250        if (list->geometry)
251            _FreeComponentNames(list->num_geometry, list->geometry);
252        bzero((char *) list, sizeof(XkbComponentListRec));
253        _XkbFree(list);
254    }
255    return;
256}
257