Separated library source code from testing code, fixing #6
[projects/chimara/chimara.git] / libchimara / charset.c
1 #include "charset.h"
2 #include "magic.h"
3 #include <glib.h>
4
5 /* Internal function: change illegal (control) characters in a string to a
6 placeholder character. Must free returned string afterwards. */
7 static gchar *
8 remove_latin1_control_characters(const unsigned char *s, const gsize len)
9 {
10         /* If len == 0, then return an empty string, not NULL */
11         if(len == 0)
12                 return g_strdup("");
13                         
14         gchar *retval = g_new0(gchar, len);
15         int i;
16         for(i = 0; i < len; i++)
17                 if( (s[i] < 32 && s[i] != 10) || (s[i] >= 127 && s[i] <= 159) )
18                         retval[i] = PLACEHOLDER;
19                 else
20                         retval[i] = s[i];
21         return retval;
22 }
23
24 /* Internal function: convert a Latin-1 string to a UTF-8 string, replacing
25 Latin-1 control characters by a placeholder first. The UTF-8 string must be
26 freed afterwards. Returns NULL on error. */
27 gchar *
28 convert_latin1_to_utf8(const gchar *s, const gsize len)
29 {
30         GError *error = NULL;
31         gchar *canonical = remove_latin1_control_characters( (unsigned char *)s,
32                 len);
33         gchar *retval = g_convert(canonical, len, "UTF-8", "ISO-8859-1", NULL, NULL, &error);
34         g_free(canonical);
35         
36         if(retval == NULL)
37                 IO_WARNING("Error during latin1->utf8 conversion of string", s, error->message);
38         
39         return retval;
40 }
41
42 /* Internal function: convert a Latin-1 string to a four-byte-per-character
43 big-endian string of gchars. The string must be freed afterwards. */
44 gchar *
45 convert_latin1_to_ucs4be_string(const gchar *s, const gsize len)
46 {
47         /* "UCS-4BE" is also a conversion type in g_convert()... but this may be more efficient */
48         gchar *retval = g_new0(gchar, len * 4);
49         int i;
50         for(i = 0; i < len; i++)
51                 retval[i * 4 + 3] = s[i];
52         return retval;
53 }
54
55 /* Internal function: convert a null-terminated UTF-8 string to a 
56 null-terminated Latin-1 string, replacing characters that cannot be represented 
57 in Latin-1 by a placeholder. If bytes_written is not NULL it will be filled with
58 the number of bytes returned, not counting the NULL terminator. The returned
59 string must be freed afterwards. Returns NULL on error. */
60 gchar *
61 convert_utf8_to_latin1(const gchar *s, gsize *bytes_written)
62 {
63         GError *error = NULL;
64         gchar *retval = g_convert_with_fallback(s, -1, "ISO-8859-1", "UTF-8", PLACEHOLDER_STRING, NULL, bytes_written, &error);
65         
66         if(retval == NULL)
67                 IO_WARNING("Error during utf8->latin1 conversion of string", s, error->message);
68
69         return retval;
70 }
71
72 /* Internal function: convert a null-terminated UTF-8 string to a
73 null-terminated UCS4 string. If items_written is not NULL it will be filled with
74 the number of code points returned, not counting the terminator. The returned
75 string must be freed afterwards. Returns NULL on error. */
76 gunichar *
77 convert_utf8_to_ucs4(const gchar *s, glong *items_written)
78 {
79         gunichar *retval = g_utf8_to_ucs4_fast(s, -1, items_written);
80         
81         if(retval == NULL)
82                 WARNING_S("Error during utf8->unicode conversion of string", s);
83
84         return retval;
85 }
86
87 /* Internal function: Convert a Unicode buffer to a null-terminated UTF-8 
88 string. The returned string must be freed afterwards. Returns NULL on error. */
89 gchar *
90 convert_ucs4_to_utf8(const gunichar *buf, const glong len)
91 {
92         GError *error = NULL;
93         gchar *retval = g_ucs4_to_utf8(buf, len, NULL, NULL, &error);
94                 
95         if(retval == NULL)
96                 WARNING_S("Error during unicode->utf8 conversion", error->message);
97                 
98         return retval;
99 }
100
101 /* Internal function: Convert a Unicode buffer to a Latin-1 string. Do not do
102 any character processing, just return values > 255 as the placeholder character.
103 The returned string must be freed afterwards.*/
104 gchar *
105 convert_ucs4_to_latin1_binary(const gunichar *buf, const glong len)
106 {
107         gchar *retval = g_new0(gchar, len);
108         int foo;
109         for(foo = 0; foo < len; foo++)
110                 retval[foo] = (buf[foo] > 255)? PLACEHOLDER : buf[foo];
111         return retval;
112 }
113
114 /* Internal function: convert a Unicode buffer to a four-byte-per-character
115 big-endian string of gchars. The string must be freed afterwards. */
116 gchar *
117 convert_ucs4_to_ucs4be_string(const gunichar *buf, const glong len)
118 {
119         gchar *retval = g_new0(gchar, len * 4);
120         int i;
121         for(i = 0; i < len; i++)
122         {
123                 retval[i * 4]     = buf[i] >> 24       ;
124                 retval[i * 4 + 1] = buf[i] >> 16 & 0xFF;
125                 retval[i * 4 + 2] = buf[i] >> 8  & 0xFF;
126                 retval[i * 4 + 3] = buf[i]       & 0xFF;
127         }
128         return retval;
129 }