move $enable_debug down below checks for GCC to avoid setting CFLAGS
[platform/upstream/glib.git] / tests / unicode-encoding.c
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <glib.h>
6
7 static gint exit_status = 0;
8
9 void
10 croak (char *format, ...)
11 {
12   va_list va;
13   
14   va_start (va, format);
15   vfprintf (stderr, format, va);
16   va_end (va);
17
18   exit (1);
19 }
20
21 void
22 fail (char *format, ...)
23 {
24   va_list va;
25   
26   va_start (va, format);
27   vfprintf (stderr, format, va);
28   va_end (va);
29
30   exit_status |= 1;
31 }
32
33 typedef enum
34 {
35   VALID,
36   INCOMPLETE,
37   NOTUNICODE,
38   OVERLONG,
39   MALFORMED
40 } Status;
41
42 static gboolean
43 ucs4_equal (gunichar *a, gunichar *b)
44 {
45   while (*a && *b && (*a == *b))
46     {
47       a++;
48       b++;
49     }
50
51   return (*a == *b);
52 }
53
54 static gboolean
55 utf16_equal (gunichar2 *a, gunichar2 *b)
56 {
57   while (*a && *b && (*a == *b))
58     {
59       a++;
60       b++;
61     }
62
63   return (*a == *b);
64 }
65
66 static gint
67 utf16_count (gunichar2 *a)
68 {
69   gint result = 0;
70   
71   while (a[result])
72     result++;
73
74   return result;
75 }
76
77 static void
78 process (gint      line,
79          gchar    *utf8,
80          Status    status,
81          gunichar *ucs4,
82          gint      ucs4_len)
83 {
84   const gchar *end;
85   gboolean is_valid = g_utf8_validate (utf8, -1, &end);
86   GError *error = NULL;
87   gint items_read, items_written;
88
89   switch (status)
90     {
91     case VALID:
92       if (!is_valid)
93         {
94           fail ("line %d: valid but g_utf8_validate returned FALSE\n", line);
95           return;
96         }
97       break;
98     case NOTUNICODE:
99     case INCOMPLETE:
100     case OVERLONG:
101     case MALFORMED:
102       if (is_valid)
103         {
104           fail ("line %d: invalid but g_utf8_validate returned TRUE\n", line);
105           return;
106         }
107       break;
108     }
109
110   if (status == INCOMPLETE)
111     {
112       gunichar *ucs4_result;      
113
114       ucs4_result = g_utf8_to_ucs4 (utf8, -1, NULL, NULL, &error);
115
116       if (!error || !g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT))
117         {
118           fail ("line %d: incomplete input not properly detected\n", line);
119           return;
120         }
121       g_clear_error (&error);
122
123       ucs4_result = g_utf8_to_ucs4 (utf8, -1, &items_read, NULL, &error);
124
125       if (!ucs4_result || items_read == strlen (utf8))
126         {
127           fail ("line %d: incomplete input not properly detected\n", line);
128           return;
129         }
130
131       g_free (ucs4_result);
132     }
133
134   if (status == VALID || status == NOTUNICODE)
135     {
136       gunichar *ucs4_result;
137       gchar *utf8_result;
138
139       ucs4_result = g_utf8_to_ucs4 (utf8, -1, &items_read, &items_written, &error);
140       if (!ucs4_result)
141         {
142           fail ("line %d: conversion to ucs4 failed: %s\n", line, error->message);
143           return;
144         }
145       
146       if (!ucs4_equal (ucs4_result, ucs4) ||
147           items_read != strlen (utf8) ||
148           items_written != ucs4_len)
149         {
150           fail ("line %d: results of conversion to ucs4 do not match expected.\n", line);
151           return;
152         }
153
154       g_free (ucs4_result);
155
156       ucs4_result = g_utf8_to_ucs4_fast (utf8, -1, &items_written);
157       
158       if (!ucs4_equal (ucs4_result, ucs4) ||
159           items_written != ucs4_len)
160         {
161           fail ("line %d: results of conversion to ucs4 do not match expected.\n", line);
162           return;
163         }
164
165       utf8_result = g_ucs4_to_utf8 (ucs4_result, -1, &items_read, &items_written, &error);
166       if (!utf8_result)
167         {
168           fail ("line %d: conversion back to utf8 failed: %s", line, error->message);
169           return;
170         }
171
172       if (strcmp (utf8_result, utf8) != 0 ||
173           items_read != ucs4_len ||
174           items_written != strlen (utf8))
175         {
176           fail ("line %d: conversion back to utf8 did not match original\n", line);
177           return;
178         }
179
180       g_free (utf8_result);
181       g_free (ucs4_result);
182     }
183
184   if (status == VALID)
185     {
186       gunichar2 *utf16_expected_tmp;
187       gunichar2 *utf16_expected;
188       gunichar2 *utf16_from_utf8;
189       gunichar2 *utf16_from_ucs4;
190       gunichar *ucs4_result;
191       gint bytes_written;
192       gint n_chars;
193       gchar *utf8_result;
194
195       if (!(utf16_expected_tmp = (gunichar2 *)g_convert (utf8, -1, "UTF-16", "UTF-8",
196                                                          NULL, &bytes_written, NULL)))
197         {
198           fail ("line %d: could not convert to UTF-16 via g_convert\n", line);
199           return;
200         }
201
202       /* zero-terminate and remove BOM
203        */
204       n_chars = bytes_written / 2;
205       if (utf16_expected_tmp[0] == 0xfeff) /* BOM */
206         {
207           n_chars--;
208           utf16_expected = g_new (gunichar2, n_chars + 1);
209           memcpy (utf16_expected, utf16_expected_tmp + 1, sizeof(gunichar2) * n_chars);
210         }
211       else if (utf16_expected_tmp[0] == 0xfffe) /* ANTI-BOM */
212         {
213           fail ("line %d: conversion via iconv to \"UTF-16\" is not native-endian\n");
214           return;
215         }
216       else
217         {
218           utf16_expected = g_new (gunichar2, n_chars + 1);
219           memcpy (utf16_expected, utf16_expected_tmp, sizeof(gunichar2) * n_chars);
220         }
221
222       utf16_expected[n_chars] = '\0';
223       
224       if (!(utf16_from_utf8 = g_utf8_to_utf16 (utf8, -1, &items_read, &items_written, &error)))
225         {
226           fail ("line %d: conversion to ucs16 failed: %s\n", line, error->message);
227           return;
228         }
229
230       if (items_read != strlen (utf8) ||
231           utf16_count (utf16_from_utf8) != items_written)
232         {
233           fail ("line %d: length error in conversion to ucs16\n", line);
234           return;
235         }
236
237       if (!(utf16_from_ucs4 = g_ucs4_to_utf16 (ucs4, -1, &items_read, &items_written, &error)))
238         {
239           fail ("line %d: conversion to ucs16 failed: %s\n", line, error->message);
240           return;
241         }
242
243       if (items_read != ucs4_len ||
244           utf16_count (utf16_from_ucs4) != items_written)
245         {
246           fail ("line %d: length error in conversion to ucs16\n", line);
247           return;
248         }
249
250       if (!utf16_equal (utf16_from_utf8, utf16_expected) ||
251           !utf16_equal (utf16_from_ucs4, utf16_expected))
252         {
253           fail ("line %d: results of conversion to ucs16 do not match\n", line);
254           return;
255         }
256
257       if (!(utf8_result = g_utf16_to_utf8 (utf16_from_utf8, -1, &items_read, &items_written, &error)))
258         {
259           fail ("line %d: conversion back to utf8 failed: %s\n", line, error->message);
260           return;
261         }
262
263       if (items_read != utf16_count (utf16_from_utf8) ||
264           items_written != strlen (utf8))
265         {
266           fail ("line %d: length error in conversion from ucs16 to utf8\n", line);
267           return;
268         }
269
270       if (!(ucs4_result = g_utf16_to_ucs4 (utf16_from_ucs4, -1, &items_read, &items_written, &error)))
271         {
272           fail ("line %d: conversion back to utf8/ucs4 failed\n", line);
273           return;
274         }
275
276       if (items_read != utf16_count (utf16_from_utf8) ||
277           items_written != ucs4_len)
278         {
279           fail ("line %d: length error in conversion from ucs16 to ucs4\n", line);
280           return;
281         }
282
283       if (strcmp (utf8, utf8_result) != 0 ||
284           !ucs4_equal (ucs4, ucs4_result))
285         {
286           fail ("line %d: conversion back to utf8/ucs4 did not match original\n", line);
287           return;
288         }
289       
290       g_free (utf16_expected_tmp);
291       g_free (utf16_expected);
292       g_free (utf16_from_utf8);
293       g_free (utf16_from_ucs4);
294       g_free (utf8_result);
295       g_free (ucs4_result);
296     }
297 }
298
299 int
300 main (int argc, char **argv)
301 {
302   gchar *srcdir = getenv ("srcdir");
303   gchar *testfile;
304   gchar *contents;
305   GError *error = NULL;
306   gchar *p, *end;
307   char *tmp;
308   gint state = 0;
309   gint line = 1;
310   gint start_line = 0;          /* Quiet GCC */
311   gchar *utf8 = NULL;           /* Quiet GCC */
312   GArray *ucs4;
313   Status status = VALID;        /* Quiet GCC */
314
315   if (!srcdir)
316     srcdir = ".";
317   
318   testfile = g_strconcat (srcdir, "/", "utf8.txt", NULL);
319   
320   g_file_get_contents (testfile, &contents, NULL, &error);
321   if (error)
322     croak ("Cannot open utf8.txt: %s", error->message);
323
324   ucs4 = g_array_new (TRUE, FALSE, sizeof(gunichar));
325
326   p = contents;
327
328   /* Loop over lines */
329   while (*p)
330     {
331       while (*p && (*p == ' ' || *p == '\t'))
332         p++;
333
334       end = p;
335       while (*end && *end != '\n')
336         end++;
337       
338       if (!*p || *p == '#' || *p == '\n')
339         goto next_line;
340
341       tmp = g_strstrip (g_strndup (p, end - p));
342       
343       switch (state)
344         {
345         case 0:
346           /* UTF-8 string */
347           start_line = line;
348           utf8 = tmp;
349           tmp = NULL;
350           break;
351           
352         case 1:
353           /* Status */
354           if (!strcmp (tmp, "VALID"))
355             status = VALID;
356           else if (!strcmp (tmp, "INCOMPLETE"))
357             status = INCOMPLETE;
358           else if (!strcmp (tmp, "NOTUNICODE"))
359             status = NOTUNICODE;
360           else if (!strcmp (tmp, "OVERLONG"))
361             status = OVERLONG;
362           else if (!strcmp (tmp, "MALFORMED"))
363             status = MALFORMED;
364           else
365             croak ("Invalid status on line %d\n", line);
366
367           if (status != VALID && status != NOTUNICODE)
368             state++;            /* No UCS-4 data */
369           
370           break;
371           
372         case 2:
373           /* UCS-4 version */
374
375           p = strtok (tmp, " \t");
376           while (p)
377             {
378               gchar *endptr;
379               
380               gunichar ch = strtoul (p, &endptr, 16);
381               if (*endptr != '\0')
382                 croak ("Invalid UCS-4 character on line %d\n", line);
383
384               g_array_append_val (ucs4, ch);
385               
386               p = strtok (NULL, " \t");
387             }
388
389           break;
390         }
391
392       g_free (tmp);
393       state = (state + 1) % 3;
394
395       if (state == 0)
396         {
397           process (start_line, utf8, status, (gunichar *)ucs4->data, ucs4->len);
398           g_array_set_size (ucs4, 0);
399           g_free (utf8);
400         }
401       
402     next_line:
403       p = end;
404       if (*p && *p == '\n')
405         p++;
406       
407       line++;
408     }
409
410   return 0;
411 }