1/*
2 * Copyright 1992, 1993 by TOSHIBA Corp.
3 *
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of TOSHIBA not be used in advertising
9 * or publicity pertaining to distribution of the software without specific,
10 * written prior permission. TOSHIBA make no representations about the
11 * suitability of this software for any purpose.  It is provided "as is"
12 * without express or implied warranty.
13 *
14 * TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 * TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 * SOFTWARE.
21 *
22 * Author: Katsuhisa Yano	TOSHIBA Corp.
23 *			   	mopi@osa.ilab.toshiba.co.jp
24 */
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29#include "Xlibint.h"
30#include "XlcPubI.h"
31#include <X11/Xutil.h>
32#include <X11/Xatom.h>
33#include "reallocarray.h"
34
35static XPointer *
36alloc_list(
37    Bool is_wide_char,
38    int count,
39    int nitems)
40{
41    if (is_wide_char) {
42	wchar_t **wstr_list;
43
44	wstr_list = Xmallocarray(count, sizeof(wchar_t *));
45	if (wstr_list == NULL)
46	    return (XPointer *) NULL;
47
48	*wstr_list = Xmallocarray(nitems, sizeof(wchar_t));
49	if (*wstr_list == NULL) {
50	    Xfree(wstr_list);
51	    return (XPointer *) NULL;
52	}
53
54	return (XPointer *) wstr_list;
55    } else {
56	char **str_list;
57
58	str_list = Xmallocarray(count, sizeof(char *));
59	if (str_list == NULL)
60	    return (XPointer *) NULL;
61
62	*str_list = Xmalloc(nitems);
63	if (*str_list == NULL) {
64	    Xfree(str_list);
65	    return (XPointer *) NULL;
66	}
67
68	return (XPointer *) str_list;
69    }
70}
71
72static void
73copy_list(
74    Bool is_wide_char,
75    XPointer text,
76    XPointer *list,
77    int count)
78{
79    int length;
80
81    if (is_wide_char) {
82	wchar_t *wc_text, *wstr, **wstr_list;
83
84	wc_text = (wchar_t *) text;
85	wstr_list = (wchar_t **) list;
86
87	for (wstr = *wstr_list; count > 0; count--, wstr_list++) {
88	    _Xwcscpy(wstr, wc_text);
89	    *wstr_list = wstr;
90	    length = _Xwcslen(wstr) + 1;
91	    wstr += length;
92	    wc_text += length;
93	}
94    } else {
95	char *mb_text, *str, **str_list;
96
97	mb_text = (char *) text;
98	str_list = (char **) list;
99
100	for (str = *str_list; count > 0; count--, str_list++) {
101	    strcpy(str, mb_text);
102	    *str_list = str;
103	    length = (int) strlen(str) + 1;
104	    str += length;
105	    mb_text += length;
106	}
107    }
108}
109
110static int
111_XTextPropertyToTextList(
112    XLCd lcd,
113    Display *dpy,
114    const XTextProperty *text_prop,
115    const char *to_type,
116    XPointer **list_ret,
117    int *count_ret)
118{
119    XlcConv conv = NULL;
120    const char *from_type;
121    XPointer from, to, buf;
122    char *str_ptr, *last_ptr;
123    Atom encoding;
124    int from_left, to_left, buf_len, ret, len;
125    int unconv_num, nitems = text_prop->nitems;
126    Bool is_wide_char = False, do_strcpy = False;
127
128    if (strcmp(XlcNWideChar, to_type) == 0)
129	is_wide_char = True;
130
131    if (nitems <= 0) {
132	*list_ret = NULL;
133	*count_ret = 0;
134	return Success;
135    }
136
137    if (text_prop->format != 8)
138	return XConverterNotFound;
139
140    encoding = text_prop->encoding;
141    if (encoding == XA_STRING)
142	from_type = XlcNString;
143    else if (encoding == XInternAtom(dpy, "UTF8_STRING", False))
144	from_type = XlcNUtf8String;
145    else if (encoding == XInternAtom(dpy, "COMPOUND_TEXT", False))
146	from_type = XlcNCompoundText;
147    else if (encoding == XInternAtom(dpy, XLC_PUBLIC(lcd, encoding_name), False))
148	from_type = XlcNMultiByte;
149    else
150	return XConverterNotFound;
151
152    if (is_wide_char) {
153	buf_len = (text_prop->nitems + 1) * sizeof(wchar_t);
154    } else {
155	if (strcmp(to_type, XlcNUtf8String) == 0)
156	    buf_len = text_prop->nitems * 6 + 1;
157	else
158	    buf_len = text_prop->nitems * XLC_PUBLIC(lcd, mb_cur_max) + 1;
159    }
160    buf = Xmalloc(buf_len);
161    if (buf == NULL)
162	return XNoMemory;
163    to = buf;
164    to_left = buf_len;
165
166    /* can be XlcNMultiByte to XlcNMultiByte,
167       or XlcNUtf8String to XlcNUtf8String */
168    if (!strcmp(from_type, to_type)) {
169        do_strcpy = True;
170    } else {
171        conv = _XlcOpenConverter(lcd, from_type, lcd, to_type);
172        if (conv == NULL) {
173	    Xfree(buf);
174	    return XConverterNotFound;
175        }
176    }
177
178    last_ptr = str_ptr = (char *) text_prop->value;
179    unconv_num = *count_ret = 0;
180
181    while (1) {
182	if (nitems == 0 || *str_ptr == 0) {
183	    from = (XPointer) last_ptr;
184	    from_left = str_ptr - last_ptr;
185	    last_ptr = str_ptr;
186
187            if (do_strcpy) {
188            	len = min(from_left, to_left);
189                strncpy(to, from, (size_t) len);
190                from += len;
191                to += len;
192                from_left -= len;
193                to_left -= len;
194                ret = 0;
195            } else {
196	        ret = _XlcConvert(conv, &from, &from_left, &to, &to_left, NULL, 0);
197            }
198
199	    if (ret < 0)
200		continue;
201
202	    unconv_num += ret;
203	    (*count_ret)++;
204
205	    if (nitems == 0)
206		break;
207 	    last_ptr = ++str_ptr;
208	    if (is_wide_char) {
209		*((wchar_t *)to) = (wchar_t) 0;
210		to += sizeof(wchar_t);
211		to_left -= sizeof(wchar_t);
212	    } else {
213		*((char *)to) = '\0';
214		to++;
215		to_left--;
216	    }
217	    if (! do_strcpy)
218	        _XlcResetConverter(conv);
219	} else
220	    str_ptr++;
221
222	nitems--;
223    }
224
225    if (! do_strcpy)
226        _XlcCloseConverter(conv);
227
228    if (is_wide_char) {
229	*((wchar_t *) to) = (wchar_t) 0;
230	to_left -= sizeof(wchar_t);
231    } else {
232	*((char *) to) = '\0';
233	to_left--;
234    }
235
236    *list_ret = alloc_list(is_wide_char, *count_ret, buf_len - to_left);
237    if (*list_ret)
238	copy_list(is_wide_char, buf, *list_ret, *count_ret);
239
240    Xfree(buf);
241
242    return unconv_num;
243}
244
245int
246_XmbTextPropertyToTextList(
247    XLCd lcd,
248    Display *dpy,
249    const XTextProperty *text_prop,
250    char ***list_ret,
251    int *count_ret)
252{
253    return _XTextPropertyToTextList(lcd, dpy, text_prop, XlcNMultiByte,
254				    (XPointer **) list_ret, count_ret);
255}
256
257int
258_XwcTextPropertyToTextList(
259    XLCd lcd,
260    Display *dpy,
261    const XTextProperty *text_prop,
262    wchar_t ***list_ret,
263    int *count_ret)
264{
265    return _XTextPropertyToTextList(lcd, dpy, text_prop, XlcNWideChar,
266				    (XPointer **) list_ret, count_ret);
267}
268
269int
270_Xutf8TextPropertyToTextList(
271    XLCd lcd,
272    Display *dpy,
273    const XTextProperty *text_prop,
274    char ***list_ret,
275    int *count_ret)
276{
277    return _XTextPropertyToTextList(lcd, dpy, text_prop, XlcNUtf8String,
278				    (XPointer **) list_ret, count_ret);
279}
280
281void
282_XwcFreeStringList(
283    XLCd lcd,
284    wchar_t **list)
285{
286    if (list) {
287        Xfree(*list);
288        Xfree(list);
289    }
290}
291