2a5c8544947a583eec616590304aaeb7cec6ed76
[platform/upstream/efl.git] / src / lib / ecore_x / xcb / ecore_xcb_textlist.c
1 #include "ecore_xcb_private.h"
2 //#include "Ecore_X_Atoms.h"
3 #include <langinfo.h>
4 #ifdef HAVE_ICONV
5 # include <iconv.h>
6 #endif
7 #ifndef CODESET
8 # define CODESET "INVALID"
9 #endif
10
11 static int _ecore_xcb_textlist_get_buffer_size(Eina_Bool is_wide,
12                                                void     *list,
13                                                int       count);
14 static int   _ecore_xcb_textlist_get_wc_len(wchar_t *wstr);
15 static void *_ecore_xcb_textlist_alloc_list(Eina_Bool is_wide,
16                                             int       count,
17                                             int       nitems);
18 static void _ecore_xcb_textlist_copy_list(Eina_Bool is_wide,
19                                           void     *text,
20                                           char    **list,
21                                           int       count);
22 static wchar_t *_ecore_xcb_textlist_copy_wchar(wchar_t *str1,
23                                                wchar_t *str2);
24 static int      _ecore_xcb_textlist_len_wchar(wchar_t *str);
25
26 #ifdef HAVE_ICONV
27 Eina_Bool
28 _ecore_xcb_utf8_textlist_to_textproperty(char                   **list,
29                                          int                      count,
30                                          Ecore_Xcb_Encoding_Style style,
31                                          Ecore_Xcb_Textproperty  *ret)
32 {
33    LOGFN(__FILE__, __LINE__, __FUNCTION__);
34
35    return _ecore_xcb_textlist_to_textproperty("utf8string", list, count,
36                                               style, ret);
37 }
38
39 #endif
40
41 Eina_Bool
42 _ecore_xcb_mb_textlist_to_textproperty(char                   **list,
43                                        int                      count,
44                                        Ecore_Xcb_Encoding_Style style,
45                                        Ecore_Xcb_Textproperty  *ret)
46 {
47    LOGFN(__FILE__, __LINE__, __FUNCTION__);
48
49    return _ecore_xcb_textlist_to_textproperty("multiByte", list, count,
50                                               style, ret);
51 }
52
53 /* NB: This Function May Not Be Correct !!!
54  * (as I do not know text conversion, locales, etc, etc very well)
55  *
56  * Portions were ripped from libX11 XTextListToTextProperty
57  */
58 Eina_Bool
59 _ecore_xcb_textlist_to_textproperty(const char              *type,
60                                     char                   **list,
61                                     int                      count,
62                                     Ecore_Xcb_Encoding_Style style,
63                                     Ecore_Xcb_Textproperty  *ret)
64 {
65    Eina_Bool is_wide = EINA_FALSE;
66    Ecore_X_Atom encoding;
67    int len = 0, nitems = 0, i = 0;
68    size_t from_left = 0, to_left = 0;
69    int unconv_num = 0, val = 0;
70    char *buff, *to, *value, *from;
71    const char *to_type, *from_type;
72    char **mb = NULL;
73    wchar_t **wc = NULL;
74 #ifdef HAVE_ICONV
75    iconv_t conv;
76 #endif
77
78    LOGFN(__FILE__, __LINE__, __FUNCTION__);
79
80    if (!strcmp("wideChar", type)) is_wide = EINA_TRUE;
81    len = _ecore_xcb_textlist_get_buffer_size(is_wide, list, count);
82    if (!(buff = (char *)malloc(len * sizeof(char)))) return EINA_FALSE;
83    from_type = nl_langinfo(CODESET);
84    switch (style)
85      {
86       case XcbStringStyle:
87       case XcbStdICCTextStyle:
88         encoding = ECORE_X_ATOM_STRING;
89         to_type = nl_langinfo(CODESET);
90 //        to_type = "string";
91         break;
92
93       case XcbUTF8StringStyle:
94         encoding = ECORE_X_ATOM_UTF8_STRING;
95         to_type = "UTF-8";
96         break;
97
98       case XcbCompoundTextStyle:
99         encoding = ECORE_X_ATOM_COMPOUND_TEXT;
100         to_type = nl_langinfo(CODESET);
101 //        to_type = "compoundText";
102         break;
103
104       case XcbTextStyle:
105         encoding = ECORE_X_ATOM_TEXT;
106         to_type = nl_langinfo(CODESET);
107 //        to_type = "multiByte";
108         if (!is_wide)
109           {
110              nitems = 0;
111              mb = (char **)list;
112              to = buff;
113              for (i = 0; ((i < count) && (len > 0)); i++)
114                {
115                   if (*mb) strcpy(to, *mb);
116                   else *to = '\0';
117                   from_left = (*mb ? strlen(*mb) : 0) + 1;
118                   nitems += from_left;
119                   to += from_left;
120                   mb++;
121                }
122              unconv_num = 0;
123              goto done;
124           }
125         break;
126
127       default:
128         free(buff);
129         return EINA_FALSE;
130         break;
131      }
132
133    if (count < 1)
134      {
135         nitems = 0;
136         goto done;
137      }
138
139 retry:
140 #ifdef HAVE_ICONV
141    conv = iconv_open(to_type, from_type);
142 #endif
143
144    if (is_wide)
145      wc = (wchar_t **)list;
146    else
147      mb = (char **)list;
148
149    to = buff;
150    to_left = len;
151    unconv_num = 0;
152    for (i = 1; to_left > 0; i++)
153      {
154         if (is_wide)
155           {
156              from = (char *)*wc;
157              from_left = _ecore_xcb_textlist_get_wc_len(*wc);
158              wc++;
159           }
160         else
161           {
162              from = *mb;
163              from_left = (*mb ? strlen(*mb) : 0);
164              mb++;
165           }
166
167 #ifdef HAVE_ICONV
168         val = iconv(conv, &from, &from_left, &to, &to_left);
169 #endif
170         if (val < 0) continue;
171         if ((val > 0) && (style == XcbStdICCTextStyle) &&
172             (encoding == ECORE_X_ATOM_STRING))
173           {
174 #ifdef HAVE_ICONV
175              iconv_close(conv);
176 #endif
177              encoding = ECORE_X_ATOM_COMPOUND_TEXT;
178              goto retry;
179           }
180
181         unconv_num += val;
182         *to++ = '\0';
183         to_left--;
184         if (i >= count) break;
185      }
186
187 #ifdef HAVE_ICONV
188    iconv_close(conv);
189 #endif
190    nitems = (to - buff);
191
192 done:
193    if (nitems <= 0) nitems = 1;
194    if (!(value = (char *)malloc(nitems * sizeof(char))))
195      {
196         free(buff);
197         return EINA_FALSE;
198      }
199    if (nitems == 1)
200      *value = 0;
201    else
202      memcpy(value, buff, nitems);
203    nitems--;
204    free(buff);
205
206    ret->value = value;
207    ret->encoding = encoding;
208    ret->format = 8;
209    ret->nitems = nitems;
210
211    return EINA_TRUE;
212 }
213
214 #ifdef HAVE_ICONV
215 Eina_Bool
216 _ecore_xcb_utf8_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
217                                          char                       ***list_ret,
218                                          int                          *count_ret)
219 {
220    LOGFN(__FILE__, __LINE__, __FUNCTION__);
221
222    return _ecore_xcb_textproperty_to_textlist(text_prop, "utf8String",
223                                               list_ret, count_ret);
224 }
225
226 #endif
227
228 Eina_Bool
229 _ecore_xcb_mb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
230                                        char                       ***list_ret,
231                                        int                          *count_ret)
232 {
233    LOGFN(__FILE__, __LINE__, __FUNCTION__);
234
235    return _ecore_xcb_textproperty_to_textlist(text_prop, "multiByte",
236                                               list_ret, count_ret);
237 }
238
239 Eina_Bool
240 _ecore_xcb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop,
241                                     const char                   *type,
242                                     char                       ***list_ret,
243                                     int                          *count_ret)
244 {
245    Eina_Bool is_wide = EINA_FALSE;
246    Eina_Bool do_strcpy = EINA_FALSE;
247    const char *from_type;
248    char *buff, *to, *from;
249    char *lptr, *sptr;
250    int nitems = 0, len = 0, num = 0, ret = 0;
251    size_t from_left = 0, to_left = 0;
252 #ifdef HAVE_ICONV
253    iconv_t conv = 0;
254 #endif
255
256    *list_ret = NULL;
257    *count_ret = 0;
258    if (!strcmp("wideChar", type)) is_wide = EINA_TRUE;
259
260    nitems = text_prop->nitems;
261    if (nitems <= 0) return EINA_TRUE;
262
263    if (text_prop->format != 8) return EINA_FALSE;
264
265    from_type = nl_langinfo(CODESET);
266    if (text_prop->encoding == ECORE_X_ATOM_UTF8_STRING)
267      from_type = "UTF-8";
268
269    if (is_wide)
270      len = (text_prop->nitems + 1) * sizeof(wchar_t);
271    else
272      {
273         if (!strcmp(type, "utf8String"))
274           len = text_prop->nitems * 6 + 1;
275         else
276           len = text_prop->nitems * MB_CUR_MAX + 1;
277      }
278
279    buff = (char *)malloc(len * sizeof(char));
280    if (!buff) return EINA_FALSE;
281
282    to = buff;
283    to_left = len;
284
285    if (!strcmp(from_type, type))
286      do_strcpy = EINA_TRUE;
287    else
288      {
289 #ifdef HAVE_ICONV
290         conv = iconv_open(type, from_type);
291 #endif
292         if (!conv)
293           {
294              free(buff);
295              return EINA_FALSE;
296           }
297      }
298
299    lptr = sptr = text_prop->value;
300    num = *count_ret = 0;
301    while (1)
302      {
303         if ((nitems == 0) || (*sptr == 0))
304           {
305              from = lptr;
306              from_left = sptr - lptr;
307              lptr = sptr;
308              if (do_strcpy)
309                {
310                   int l = 0;
311
312                   l = MIN(from_left, to_left);
313                   strncpy(to, from, l);
314                   from += len;
315                   to += len;
316                   from_left -= l;
317                   to_left -= l;
318                   ret = 0;
319                }
320              else
321                ret = iconv(conv, &from, &from_left, &to, &to_left);
322
323              if (ret < 0) continue;
324              num += ret;
325              (*count_ret)++;
326              if (nitems == 0) break;
327              lptr = ++sptr;
328              if (is_wide)
329                {
330                   *((wchar_t *)to) = (wchar_t)0;
331                   to += sizeof(wchar_t);
332                   to_left -= sizeof(wchar_t);
333                }
334              else
335                {
336                   *((char *)to) = '\0';
337                   to++;
338                   to_left--;
339                }
340           }
341         else
342           sptr++;
343
344         nitems--;
345      }
346
347 #if HAVE_ICONV
348    if (!do_strcpy) iconv_close(conv);
349 #endif
350
351    if (is_wide)
352      {
353         *((wchar_t *)to) = (wchar_t)0;
354         to_left -= sizeof(wchar_t);
355      }
356    else
357      {
358         *((char *)to) = '\0';
359         to_left--;
360      }
361
362    *list_ret =
363      _ecore_xcb_textlist_alloc_list(is_wide, *count_ret, (len - to_left));
364    if (*list_ret)
365      _ecore_xcb_textlist_copy_list(is_wide, buff, *list_ret, *count_ret);
366
367    free(buff);
368
369    return EINA_TRUE;
370 }
371
372 static int
373 _ecore_xcb_textlist_get_buffer_size(Eina_Bool is_wide,
374                                     void     *list,
375                                     int       count)
376 {
377    int len = 0;
378    char **mb;
379    wchar_t **wc;
380
381    if (!list) return 0;
382    if (is_wide)
383      {
384         wc = (wchar_t **)list;
385         for (; count-- > 0; wc++)
386           if (*wc) len += _ecore_xcb_textlist_get_wc_len(*wc) + 1;
387         len *= 5;
388      }
389    else
390      {
391         mb = (char **)list;
392         for (; count-- > 0; mb++)
393           if (*mb) len += strlen(*mb) + 1;
394         len *= 3;
395      }
396    len = (len / 2048 + 1) * 2048;
397    return len;
398 }
399
400 static int
401 _ecore_xcb_textlist_get_wc_len(wchar_t *wstr)
402 {
403    wchar_t *ptr;
404
405    ptr = wstr;
406    while (*ptr)
407      ptr++;
408
409    return ptr - wstr;
410 }
411
412 static void *
413 _ecore_xcb_textlist_alloc_list(Eina_Bool is_wide,
414                                int       count,
415                                int       nitems)
416 {
417    if (is_wide)
418      {
419         wchar_t **list;
420
421         list = (wchar_t **)malloc(count * sizeof(wchar_t *));
422         if (!list) return NULL;
423         *list = (wchar_t *)malloc(nitems * sizeof(wchar_t));
424         if (!*list)
425           {
426              free(list);
427              return NULL;
428           }
429         return *list;
430      }
431    else
432      {
433         char **list;
434
435         list = (char **)malloc(count * sizeof(char *));
436         if (!list) return NULL;
437         *list = (char *)malloc(nitems * sizeof(char));
438         if (!*list)
439           {
440              free(list);
441              return NULL;
442           }
443         return *list;
444      }
445 }
446
447 static void
448 _ecore_xcb_textlist_copy_list(Eina_Bool is_wide,
449                               void     *text,
450                               char    **list,
451                               int       count)
452 {
453    int len = 0;
454
455    if (is_wide)
456      {
457         wchar_t *txt, *str, **wlist;
458
459         txt = (wchar_t *)text;
460         wlist = (wchar_t **)list;
461         for (str = *wlist; count > 0; count--, wlist++)
462           {
463              _ecore_xcb_textlist_copy_wchar(str, txt);
464              *wlist = str;
465              len = (_ecore_xcb_textlist_len_wchar(str) + 1);
466              str += len;
467              txt += len;
468           }
469      }
470    else
471      {
472         char *txt, *str, **slist;
473
474         txt = (char *)text;
475         slist = (char **)list;
476         for (str = *slist; count > 0; count--, slist++)
477           {
478              strcpy(str, txt);
479              *slist = str;
480              len = strlen(str) + 1;
481              str += len;
482              txt += len;
483           }
484      }
485 }
486
487 static wchar_t *
488 _ecore_xcb_textlist_copy_wchar(wchar_t *str1,
489                                wchar_t *str2)
490 {
491    wchar_t *tmp;
492
493    tmp = str1;
494    while ((*str1++ = *str2++))
495      ;
496    return tmp;
497 }
498
499 static int
500 _ecore_xcb_textlist_len_wchar(wchar_t *str)
501 {
502    wchar_t *ptr;
503
504    ptr = str;
505    while (*ptr)
506      ptr++;
507    return ptr - str;
508 }
509