2 * gunicode.c: Some Unicode routines
5 * Miguel de Icaza (miguel@novell.com)
7 * (C) 2006 Novell, Inc.
9 * utf8 validation code came from:
10 * libxml2-2.6.26 licensed under the MIT X11 license
12 * Authors credit in libxml's string.c:
13 * William Brack <wbrack@mmm.com.hk>
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
24 * The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 #include <unicode-data.h>
42 #if defined(_MSC_VER) || defined(G_OS_WIN32)
47 # ifdef HAVE_LANGINFO_H
48 # include <langinfo.h>
50 # ifdef HAVE_LOCALCHARSET_H
51 # include <localcharset.h>
55 static const char *my_charset
;
56 static gboolean is_utf8
;
59 * Character set conversion
63 g_unichar_type (gunichar c
)
67 guint16 cp
= (guint16
) c
;
68 for (i
= 0; i
< unicode_category_ranges_count
; i
++) {
69 if (cp
< unicode_category_ranges
[i
].start
)
71 if (unicode_category_ranges
[i
].end
<= cp
)
73 return unicode_category
[i
] [cp
- unicode_category_ranges
[i
].start
];
77 // 3400-4DB5: OtherLetter
78 // 4E00-9FC3: OtherLetter
79 // AC00-D7A3: OtherLetter
80 // D800-DFFF: OtherSurrogate
81 // E000-F8FF: OtherPrivateUse
82 // 20000-2A6D6 OtherLetter
83 // F0000-FFFFD OtherPrivateUse
84 // 100000-10FFFD OtherPrivateUse
86 if (0x3400 <= cp
&& cp
< 0x4DB5)
87 return G_UNICODE_OTHER_LETTER
;
88 if (0x4E00 <= cp
&& cp
< 0x9FC3)
89 return G_UNICODE_OTHER_LETTER
;
90 if (0xAC00<= cp
&& cp
< 0xD7A3)
91 return G_UNICODE_OTHER_LETTER
;
92 if (0xD800 <= cp
&& cp
< 0xDFFF)
93 return G_UNICODE_SURROGATE
;
94 if (0xE000 <= cp
&& cp
< 0xF8FF)
95 return G_UNICODE_PRIVATE_USE
;
96 /* since the argument is UTF-16, we cannot check beyond FFFF */
98 /* It should match any of above */
103 g_unichar_break_type (gunichar c
)
106 return G_UNICODE_BREAK_UNKNOWN
;
110 g_unichar_case (gunichar c
, gboolean upper
)
113 guint32 cp
= (guint32
) c
, v
;
115 for (i
= 0; i
< simple_case_map_ranges_count
; i
++) {
116 if (cp
< simple_case_map_ranges
[i
].start
)
118 if (simple_case_map_ranges
[i
].end
<= cp
)
121 const guint16
*tab
= upper
? simple_upper_case_mapping_lowarea
[i
] : simple_lower_case_mapping_lowarea
[i
];
122 v
= tab
[cp
- simple_case_map_ranges
[i
].start
];
125 i2
= (gint8
)(i
- (upper
? simple_upper_case_mapping_lowarea_table_count
: simple_lower_case_mapping_lowarea_table_count
));
126 tab
= upper
? simple_upper_case_mapping_higharea
[i2
] : simple_lower_case_mapping_higharea
[i2
];
127 v
= tab
[cp
- simple_case_map_ranges
[i
].start
];
129 return v
!= 0 ? (gunichar
) v
: c
;
135 g_unichar_toupper (gunichar c
)
137 return g_unichar_case (c
, TRUE
);
141 g_unichar_tolower (gunichar c
)
143 return g_unichar_case (c
, FALSE
);
147 g_unichar_totitle (gunichar c
)
153 for (i
= 0; i
< simple_titlecase_mapping_count
; i
++) {
154 if (simple_titlecase_mapping
[i
].codepoint
== cp
)
155 return simple_titlecase_mapping
[i
].title
;
156 if (simple_titlecase_mapping
[i
].codepoint
> cp
)
157 /* it is ordered, hence no more match */
160 return g_unichar_toupper (c
);
164 g_unichar_isxdigit (gunichar c
)
166 return (g_unichar_xdigit_value (c
) != -1);
171 g_unichar_xdigit_value (gunichar c
)
173 if (c
>= 0x30 && c
<= 0x39) /*0-9*/
175 if (c
>= 0x41 && c
<= 0x46) /*A-F*/
177 if (c
>= 0x61 && c
<= 0x66) /*a-f*/
183 g_unichar_isspace (gunichar c
)
185 GUnicodeType type
= g_unichar_type (c
);
186 if (type
== G_UNICODE_LINE_SEPARATOR
||
187 type
== G_UNICODE_PARAGRAPH_SEPARATOR
||
188 type
== G_UNICODE_SPACE_SEPARATOR
)
196 * This is broken, and assumes an UTF8 system, but will do for eglib's first user
199 g_filename_from_utf8 (const gchar
*utf8string
, gssize len
, gsize
*bytes_read
, gsize
*bytes_written
, GError
**error
)
204 len
= strlen (utf8string
);
206 res
= g_malloc (len
+ 1);
207 g_strlcpy (res
, utf8string
, len
+ 1);
212 g_get_charset (G_CONST_RETURN
char **charset
)
214 if (my_charset
== NULL
) {
216 static char buf
[14];
217 sprintf (buf
, "CP%u", GetACP ());
221 /* These shouldn't be heap allocated */
222 #if defined(HAVE_LANGINFO_H)
223 my_charset
= nl_langinfo (CODESET
);
224 #elif defined(HAVE_LOCALCHARSET_H)
225 my_charset
= locale_charset ();
227 my_charset
= "UTF-8";
229 is_utf8
= strcmp (my_charset
, "UTF-8") == 0;
234 *charset
= my_charset
;
240 g_locale_to_utf8 (const gchar
*opsysstring
, gssize len
, gsize
*bytes_read
, gsize
*bytes_written
, GError
**error
)
242 g_get_charset (NULL
);
244 return g_convert (opsysstring
, len
, "UTF-8", my_charset
, bytes_read
, bytes_written
, error
);
248 g_locale_from_utf8 (const gchar
*utf8string
, gssize len
, gsize
*bytes_read
, gsize
*bytes_written
, GError
**error
)
250 g_get_charset (NULL
);
252 return g_convert (utf8string
, len
, my_charset
, "UTF-8", bytes_read
, bytes_written
, error
);