]> git.sur5r.net Git - i3/i3/blob - libi3/ucs2_conversion.c
Consolidate all convert_* functions into libi3.
[i3/i3] / libi3 / ucs2_conversion.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  */
8 #include <err.h>
9 #include <errno.h>
10 #include <iconv.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "libi3.h"
15
16 static iconv_t utf8_conversion_descriptor = (iconv_t)-1;
17 static iconv_t ucs2_conversion_descriptor = (iconv_t)-1;
18
19 /*
20  * Converts the given string to UTF-8 from UCS-2 big endian. The return value
21  * must be freed after use.
22  *
23  */
24 char *convert_ucs2_to_utf8(xcb_char2b_t *text, size_t num_glyphs) {
25     /* Allocate the output buffer (UTF-8 is at most 4 bytes per glyph) */
26     size_t buffer_size = num_glyphs * 4 * sizeof(char) + 1;
27     char *buffer = scalloc(buffer_size * sizeof(char));
28
29     /* We need to use an additional pointer, because iconv() modifies it */
30     char *output = buffer;
31     size_t output_size = buffer_size - 1;
32
33     if (utf8_conversion_descriptor == (iconv_t)-1) {
34         /* Get a new conversion descriptor */
35         utf8_conversion_descriptor = iconv_open("UTF-8", "UCS-2BE");
36         if (utf8_conversion_descriptor == (iconv_t)-1)
37             err(EXIT_FAILURE, "Error opening the conversion context");
38     }
39     else {
40         /* Reset the existing conversion descriptor */
41         iconv(utf8_conversion_descriptor, NULL, NULL, NULL, NULL);
42     }
43
44     /* Do the conversion */
45     size_t input_len = num_glyphs * sizeof(xcb_char2b_t);
46     size_t rc = iconv(utf8_conversion_descriptor, (char**)&text,
47             &input_len, &output, &output_size);
48     if (rc == (size_t)-1) {
49         perror("Converting to UTF-8 failed");
50         free(buffer);
51         return NULL;
52     }
53
54     return buffer;
55 }
56
57 /*
58  * Converts the given string to UCS-2 big endian for use with
59  * xcb_image_text_16(). The amount of real glyphs is stored in real_strlen,
60  * a buffer containing the UCS-2 encoded string (16 bit per glyph) is
61  * returned. It has to be freed when done.
62  *
63  */
64 xcb_char2b_t *convert_utf8_to_ucs2(char *input, int *real_strlen) {
65     /* Calculate the input buffer size (UTF-8 is strlen-safe) */
66     size_t input_size = strlen(input);
67
68     /* Calculate the output buffer size and allocate the buffer */
69     size_t buffer_size = input_size * sizeof(xcb_char2b_t);
70     xcb_char2b_t *buffer = smalloc(buffer_size);
71
72     /* We need to use an additional pointer, because iconv() modifies it */
73     size_t output_size = buffer_size;
74     xcb_char2b_t *output = buffer;
75
76     if (ucs2_conversion_descriptor == (iconv_t)-1) {
77         /* Get a new conversion descriptor */
78         ucs2_conversion_descriptor = iconv_open("UCS-2BE", "UTF-8");
79         if (ucs2_conversion_descriptor == (iconv_t)-1)
80             err(EXIT_FAILURE, "Error opening the conversion context");
81     }
82     else {
83         /* Reset the existing conversion descriptor */
84         iconv(ucs2_conversion_descriptor, NULL, NULL, NULL, NULL);
85     }
86
87     /* Do the conversion */
88     size_t rc = iconv(ucs2_conversion_descriptor, (char**)&input,
89             &input_size, (char**)&output, &output_size);
90     if (rc == (size_t)-1) {
91         perror("Converting to UCS-2 failed");
92         free(buffer);
93         if (real_strlen != NULL)
94             *real_strlen = 0;
95         return NULL;
96     }
97
98     /* Return the resulting string's length */
99     if (real_strlen != NULL)
100         *real_strlen = (buffer_size - output_size) / sizeof(xcb_char2b_t);
101
102     return buffer;
103 }