109 lines
3.7 KiB
C
109 lines
3.7 KiB
C
/*
|
|
* vim:ts=4:sw=4:expandtab
|
|
*
|
|
* i3 - an improved dynamic tiling window manager
|
|
* © 2009 Michael Stapelberg and contributors (see also: LICENSE)
|
|
*
|
|
*/
|
|
#include "libi3.h"
|
|
|
|
#include <err.h>
|
|
#include <iconv.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static iconv_t utf8_conversion_descriptor = (iconv_t)-1;
|
|
static iconv_t ucs2_conversion_descriptor = (iconv_t)-1;
|
|
|
|
/*
|
|
* Converts the given string to UTF-8 from UCS-2 big endian. The return value
|
|
* must be freed after use.
|
|
*
|
|
*/
|
|
char *convert_ucs2_to_utf8(xcb_char2b_t *text, size_t num_glyphs) {
|
|
/* Allocate the output buffer (UTF-8 is at most 4 bytes per glyph) */
|
|
size_t buffer_size = num_glyphs * 4 + 1;
|
|
char *buffer = scalloc(buffer_size, 1);
|
|
|
|
/* We need to use an additional pointer, because iconv() modifies it */
|
|
char *output = buffer;
|
|
size_t output_size = buffer_size - 1;
|
|
|
|
if (utf8_conversion_descriptor == (iconv_t)-1) {
|
|
/* Get a new conversion descriptor */
|
|
utf8_conversion_descriptor = iconv_open("UTF-8", "UCS-2BE");
|
|
if (utf8_conversion_descriptor == (iconv_t)-1)
|
|
err(EXIT_FAILURE, "Error opening the conversion context");
|
|
} else {
|
|
/* Reset the existing conversion descriptor */
|
|
iconv(utf8_conversion_descriptor, NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
/* Do the conversion */
|
|
size_t input_len = num_glyphs * sizeof(xcb_char2b_t);
|
|
size_t rc = iconv(utf8_conversion_descriptor, (char **)&text,
|
|
&input_len, &output, &output_size);
|
|
if (rc == (size_t)-1) {
|
|
perror("Converting to UTF-8 failed");
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
/*
|
|
* Converts the given string to UCS-2 big endian for use with
|
|
* xcb_image_text_16(). The amount of real glyphs is stored in real_strlen,
|
|
* a buffer containing the UCS-2 encoded string (16 bit per glyph) is
|
|
* returned. It has to be freed when done.
|
|
*
|
|
*/
|
|
xcb_char2b_t *convert_utf8_to_ucs2(char *input, size_t *real_strlen) {
|
|
/* Calculate the input buffer size (UTF-8 is strlen-safe) */
|
|
size_t input_size = strlen(input);
|
|
|
|
/* Calculate the output buffer size and allocate the buffer */
|
|
size_t buffer_size = input_size * sizeof(xcb_char2b_t);
|
|
xcb_char2b_t *buffer = smalloc(buffer_size);
|
|
|
|
/* We need to use an additional pointer, because iconv() modifies it */
|
|
size_t output_bytes_left = buffer_size;
|
|
xcb_char2b_t *output = buffer;
|
|
|
|
if (ucs2_conversion_descriptor == (iconv_t)-1) {
|
|
/* Get a new conversion descriptor. //IGNORE is a GNU suffix that makes
|
|
* iconv to silently discard characters that cannot be represented in
|
|
* the target character set. */
|
|
ucs2_conversion_descriptor = iconv_open("UCS-2BE//IGNORE", "UTF-8");
|
|
if (ucs2_conversion_descriptor == (iconv_t)-1) {
|
|
ucs2_conversion_descriptor = iconv_open("UCS-2BE", "UTF-8");
|
|
}
|
|
if (ucs2_conversion_descriptor == (iconv_t)-1) {
|
|
err(EXIT_FAILURE, "Error opening the conversion context");
|
|
}
|
|
} else {
|
|
/* Reset the existing conversion descriptor */
|
|
iconv(ucs2_conversion_descriptor, NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
/* Do the conversion */
|
|
size_t rc = iconv(ucs2_conversion_descriptor, &input, &input_size,
|
|
(char **)&output, &output_bytes_left);
|
|
if (rc == (size_t)-1) {
|
|
/* Conversion will only be partial. */
|
|
perror("Converting to UCS-2 failed");
|
|
}
|
|
|
|
/* If no bytes where converted, this is equivalent to freeing buffer. */
|
|
buffer_size -= output_bytes_left;
|
|
buffer = srealloc(buffer, buffer_size);
|
|
|
|
/* Return the resulting string's length */
|
|
if (real_strlen != NULL) {
|
|
*real_strlen = buffer_size / sizeof(xcb_char2b_t);
|
|
}
|
|
|
|
return buffer;
|
|
}
|