~ubuntu-branches/ubuntu/karmic/moon/karmic

« back to all changes in this revision

Viewing changes to cairo/src/cairo-unicode.c

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-14 12:01:08 UTC
  • Revision ID: james.westby@ubuntu.com-20090214120108-06539vb25vhbd8bn
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
 
2
/* cairo - a vector graphics library with display and print output
 
3
 *
 
4
 * The code in this file is derived from GLib's gutf8.c and
 
5
 *   ultimately from libunicode. It is relicensed under the
 
6
 *   dual LGPL/MPL with permission of the original authors.
 
7
 *
 
8
 * Copyright Ā© 1999 Tom Tromey
 
9
 * Copyright Ā© 2005 Red Hat, Inc
 
10
 *
 
11
 * This library is free software; you can redistribute it and/or
 
12
 * modify it either under the terms of the GNU Lesser General Public
 
13
 * License version 2.1 as published by the Free Software Foundation
 
14
 * (the "LGPL") or, at your option, under the terms of the Mozilla
 
15
 * Public License Version 1.1 (the "MPL"). If you do not alter this
 
16
 * notice, a recipient may use your version of this file under either
 
17
 * the MPL or the LGPL.
 
18
 *
 
19
 * You should have received a copy of the LGPL along with this library
 
20
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
22
 * You should have received a copy of the MPL along with this library
 
23
 * in the file COPYING-MPL-1.1
 
24
 *
 
25
 * The contents of this file are subject to the Mozilla Public License
 
26
 * Version 1.1 (the "License"); you may not use this file except in
 
27
 * compliance with the License. You may obtain a copy of the License at
 
28
 * http://www.mozilla.org/MPL/
 
29
 *
 
30
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 
31
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 
32
 * the specific language governing rights and limitations.
 
33
 *
 
34
 * The Original Code is the cairo graphics library.
 
35
 *
 
36
 * The Initial Developer of the Original Code is Tom Tromey.
 
37
 *  and Red Hat, Inc.
 
38
 *
 
39
 * Contributor(s):
 
40
 *      Owen Taylor <otaylor@redhat.com>
 
41
 */
 
42
 
 
43
#include "cairoint.h"
 
44
 
 
45
#define UTF8_COMPUTE(Char, Mask, Len)                                         \
 
46
  if (Char < 128)                                                             \
 
47
    {                                                                         \
 
48
      Len = 1;                                                                \
 
49
      Mask = 0x7f;                                                            \
 
50
    }                                                                         \
 
51
  else if ((Char & 0xe0) == 0xc0)                                             \
 
52
    {                                                                         \
 
53
      Len = 2;                                                                \
 
54
      Mask = 0x1f;                                                            \
 
55
    }                                                                         \
 
56
  else if ((Char & 0xf0) == 0xe0)                                             \
 
57
    {                                                                         \
 
58
      Len = 3;                                                                \
 
59
      Mask = 0x0f;                                                            \
 
60
    }                                                                         \
 
61
  else if ((Char & 0xf8) == 0xf0)                                             \
 
62
    {                                                                         \
 
63
      Len = 4;                                                                \
 
64
      Mask = 0x07;                                                            \
 
65
    }                                                                         \
 
66
  else if ((Char & 0xfc) == 0xf8)                                             \
 
67
    {                                                                         \
 
68
      Len = 5;                                                                \
 
69
      Mask = 0x03;                                                            \
 
70
    }                                                                         \
 
71
  else if ((Char & 0xfe) == 0xfc)                                             \
 
72
    {                                                                         \
 
73
      Len = 6;                                                                \
 
74
      Mask = 0x01;                                                            \
 
75
    }                                                                         \
 
76
  else                                                                        \
 
77
    Len = -1;
 
78
 
 
79
#define UTF8_LENGTH(Char)              \
 
80
  ((Char) < 0x80 ? 1 :                 \
 
81
   ((Char) < 0x800 ? 2 :               \
 
82
    ((Char) < 0x10000 ? 3 :            \
 
83
     ((Char) < 0x200000 ? 4 :          \
 
84
      ((Char) < 0x4000000 ? 5 : 6)))))
 
85
 
 
86
#define UTF8_GET(Result, Chars, Count, Mask, Len)                             \
 
87
  (Result) = (Chars)[0] & (Mask);                                             \
 
88
  for ((Count) = 1; (Count) < (Len); ++(Count))                               \
 
89
    {                                                                         \
 
90
      if (((Chars)[(Count)] & 0xc0) != 0x80)                                  \
 
91
        {                                                                     \
 
92
          (Result) = -1;                                                      \
 
93
          break;                                                              \
 
94
        }                                                                     \
 
95
      (Result) <<= 6;                                                         \
 
96
      (Result) |= ((Chars)[(Count)] & 0x3f);                                  \
 
97
    }
 
98
 
 
99
#define UNICODE_VALID(Char)                   \
 
100
    ((Char) < 0x110000 &&                     \
 
101
     (((Char) & 0xFFFFF800) != 0xD800) &&     \
 
102
     ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
 
103
     ((Char) & 0xFFFE) != 0xFFFE)
 
104
 
 
105
static const char utf8_skip_data[256] = {
 
106
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
107
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
108
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
109
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
110
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
111
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 
112
    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
 
113
    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
 
114
};
 
115
 
 
116
#define UTF8_NEXT_CHAR(p) ((p) + utf8_skip_data[*(unsigned char *)(p)])
 
117
 
 
118
/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
 
119
 * If @p does not point to a valid UTF-8 encoded character, results are
 
120
 * undefined.
 
121
 **/
 
122
static uint32_t
 
123
_utf8_get_char (const unsigned char *p)
 
124
{
 
125
    int i, mask = 0, len;
 
126
    uint32_t result;
 
127
    unsigned char c = (unsigned char) *p;
 
128
 
 
129
    UTF8_COMPUTE (c, mask, len);
 
130
    if (len == -1)
 
131
        return (uint32_t)-1;
 
132
    UTF8_GET (result, p, i, mask, len);
 
133
 
 
134
    return result;
 
135
}
 
136
 
 
137
/* Like _utf8_get_char, but take a maximum length
 
138
 * and return (uint32_t)-2 on incomplete trailing character
 
139
 */
 
140
static uint32_t
 
141
_utf8_get_char_extended (const unsigned char *p,
 
142
                         long                 max_len)
 
143
{
 
144
    int i, len;
 
145
    uint32_t wc = (unsigned char) *p;
 
146
 
 
147
    if (wc < 0x80) {
 
148
        return wc;
 
149
    } else if (wc < 0xc0) {
 
150
        return (uint32_t)-1;
 
151
    } else if (wc < 0xe0) {
 
152
        len = 2;
 
153
        wc &= 0x1f;
 
154
    } else if (wc < 0xf0) {
 
155
        len = 3;
 
156
        wc &= 0x0f;
 
157
    } else if (wc < 0xf8) {
 
158
        len = 4;
 
159
        wc &= 0x07;
 
160
    } else if (wc < 0xfc) {
 
161
        len = 5;
 
162
        wc &= 0x03;
 
163
    } else if (wc < 0xfe) {
 
164
        len = 6;
 
165
        wc &= 0x01;
 
166
    } else {
 
167
        return (uint32_t)-1;
 
168
    }
 
169
 
 
170
    if (max_len >= 0 && len > max_len) {
 
171
        for (i = 1; i < max_len; i++) {
 
172
            if ((((unsigned char *)p)[i] & 0xc0) != 0x80)
 
173
                return (uint32_t)-1;
 
174
        }
 
175
        return (uint32_t)-2;
 
176
    }
 
177
 
 
178
    for (i = 1; i < len; ++i) {
 
179
        uint32_t ch = ((unsigned char *)p)[i];
 
180
 
 
181
        if ((ch & 0xc0) != 0x80) {
 
182
            if (ch)
 
183
                return (uint32_t)-1;
 
184
            else
 
185
                return (uint32_t)-2;
 
186
        }
 
187
 
 
188
        wc <<= 6;
 
189
        wc |= (ch & 0x3f);
 
190
    }
 
191
 
 
192
    if (UTF8_LENGTH(wc) != len)
 
193
        return (uint32_t)-1;
 
194
 
 
195
    return wc;
 
196
}
 
197
 
 
198
/**
 
199
 * _cairo_utf8_get_char_validated:
 
200
 * @p: a UTF-8 string
 
201
 * @unicode: location to store one Unicode character
 
202
 *
 
203
 * Decodes the first character of a valid UTF-8 string, and returns
 
204
 * the number of bytes consumed.
 
205
 *
 
206
 * Note that the string should be valid.  Do not use this without
 
207
 * validating the string first.
 
208
 *
 
209
 * Returns: the number of bytes forming the character returned.
 
210
 **/
 
211
int
 
212
_cairo_utf8_get_char_validated (const char *p,
 
213
                                uint32_t   *unicode)
 
214
{
 
215
    int i, mask = 0, len;
 
216
    uint32_t result;
 
217
    unsigned char c = (unsigned char) *p;
 
218
 
 
219
    UTF8_COMPUTE (c, mask, len);
 
220
    if (len == -1) {
 
221
        if (unicode)
 
222
            *unicode = (uint32_t)-1;
 
223
        return 1;
 
224
    }
 
225
    UTF8_GET (result, p, i, mask, len);
 
226
 
 
227
    if (unicode)
 
228
        *unicode = result;
 
229
    return len;
 
230
}
 
231
 
 
232
/**
 
233
 * _cairo_utf8_to_utf32:
 
234
 * @str: an UTF-8 string
 
235
 * @len: length of @str in bytes, or -1 if it is nul-terminated.
 
236
 *   If @len is supplied and the string has an embedded nul
 
237
 *   byte, only the portion before the nul byte is converted.
 
238
 * @result: location to store a pointer to a newly allocated UTF-32
 
239
 *   string (always native endian), or %NULL. Free with free(). A 0
 
240
 *   word will be written after the last character.
 
241
 * @items_written: location to store number of 32-bit words
 
242
 *   written. (Not including the trailing 0)
 
243
 *
 
244
 * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode
 
245
 * with 1 32-bit word per character. The string is validated to
 
246
 * consist entirely of valid Unicode characters.
 
247
 *
 
248
 * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
 
249
 *   successfully converted. %CAIRO_STATUS_INVALID_STRING if an
 
250
 *   an invalid sequence was found.
 
251
 **/
 
252
cairo_status_t
 
253
_cairo_utf8_to_ucs4 (const char *str,
 
254
                     int         len,
 
255
                     uint32_t  **result,
 
256
                     int        *items_written)
 
257
{
 
258
    uint32_t *str32 = NULL;
 
259
    int n_chars, i;
 
260
    const unsigned char *in;
 
261
    const unsigned char * const ustr = (const unsigned char *) str;
 
262
 
 
263
    in = ustr;
 
264
    n_chars = 0;
 
265
    while ((len < 0 || ustr + len - in > 0) && *in)
 
266
    {
 
267
        uint32_t wc = _utf8_get_char_extended (in, ustr + len - in);
 
268
        if (wc & 0x80000000 || !UNICODE_VALID (wc))
 
269
            return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
270
 
 
271
        n_chars++;
 
272
        if (n_chars == INT_MAX)
 
273
            return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
274
 
 
275
        in = UTF8_NEXT_CHAR (in);
 
276
    }
 
277
 
 
278
    if (result) {
 
279
        str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
 
280
        if (!str32)
 
281
            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
282
 
 
283
        in = ustr;
 
284
        for (i=0; i < n_chars; i++) {
 
285
            str32[i] = _utf8_get_char (in);
 
286
            in = UTF8_NEXT_CHAR (in);
 
287
        }
 
288
        str32[i] = 0;
 
289
 
 
290
        *result = str32;
 
291
    }
 
292
 
 
293
    if (items_written)
 
294
        *items_written = n_chars;
 
295
 
 
296
    return CAIRO_STATUS_SUCCESS;
 
297
}
 
298
 
 
299
/**
 
300
 * _cairo_ucs4_to_utf8:
 
301
 * @unicode: a UCS-4 character
 
302
 * @utf8: buffer to write utf8 string into. Must have at least 4 bytes
 
303
 * space available. Or %NULL.
 
304
 *
 
305
 * Return value: Number of bytes in the utf8 string or 0 if an invalid
 
306
 * unicode character
 
307
 **/
 
308
int
 
309
_cairo_ucs4_to_utf8 (uint32_t  unicode,
 
310
                     char     *utf8)
 
311
{
 
312
    int bytes;
 
313
    char *p;
 
314
 
 
315
    if (unicode < 0x80) {
 
316
        if (utf8)
 
317
            *utf8 = unicode;
 
318
        return 1;
 
319
    } else if (unicode < 0x800) {
 
320
        bytes = 2;
 
321
    } else if (unicode < 0x10000) {
 
322
        bytes = 3;
 
323
    } else if (unicode < 0x200000) {
 
324
        bytes = 4;
 
325
    } else {
 
326
        return 0;
 
327
    }
 
328
 
 
329
    if (!utf8)
 
330
        return bytes;
 
331
 
 
332
    p = utf8 + bytes;
 
333
    while (p > utf8) {
 
334
        *--p = 0x80 | (unicode & 0x3f);
 
335
        unicode >>= 6;
 
336
    }
 
337
    *p |= 0xf0 << (4 - bytes);
 
338
 
 
339
    return bytes;
 
340
}
 
341
 
 
342
#if CAIRO_HAS_UTF8_TO_UTF16
 
343
/**
 
344
 * _cairo_utf8_to_utf16:
 
345
 * @str: an UTF-8 string
 
346
 * @len: length of @str in bytes, or -1 if it is nul-terminated.
 
347
 *   If @len is supplied and the string has an embedded nul
 
348
 *   byte, only the portion before the nul byte is converted.
 
349
 * @result: location to store a pointer to a newly allocated UTF-16
 
350
 *   string (always native endian). Free with free(). A 0
 
351
 *   word will be written after the last character.
 
352
 * @items_written: location to store number of 16-bit words
 
353
 *   written. (Not including the trailing 0)
 
354
 *
 
355
 * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode
 
356
 * where characters are represented either as a single 16-bit word, or
 
357
 * as a pair of 16-bit "surrogates". The string is validated to
 
358
 * consist entirely of valid Unicode characters.
 
359
 *
 
360
 * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
 
361
 *   successfully converted. %CAIRO_STATUS_INVALID_STRING if an
 
362
 *   an invalid sequence was found.
 
363
 **/
 
364
cairo_status_t
 
365
_cairo_utf8_to_utf16 (const char *str,
 
366
                      int         len,
 
367
                      uint16_t **result,
 
368
                      int       *items_written)
 
369
{
 
370
    uint16_t *str16 = NULL;
 
371
    int n16, i;
 
372
    const unsigned char *in;
 
373
    const unsigned char * const ustr = (const unsigned char *) str;
 
374
 
 
375
    in = ustr;
 
376
    n16 = 0;
 
377
    while ((len < 0 || ustr + len - in > 0) && *in) {
 
378
        uint32_t wc = _utf8_get_char_extended (in, ustr + len - in);
 
379
        if (wc & 0x80000000 || !UNICODE_VALID (wc))
 
380
            return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
381
 
 
382
        if (wc < 0x10000)
 
383
            n16 += 1;
 
384
        else
 
385
            n16 += 2;
 
386
 
 
387
        if (n16 == INT_MAX - 1 || n16 == INT_MAX)
 
388
            return _cairo_error (CAIRO_STATUS_INVALID_STRING);
 
389
 
 
390
        in = UTF8_NEXT_CHAR (in);
 
391
    }
 
392
 
 
393
    str16 = _cairo_malloc_ab (n16 + 1, sizeof (uint16_t));
 
394
    if (!str16)
 
395
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
396
 
 
397
    in = ustr;
 
398
    for (i = 0; i < n16;) {
 
399
        uint32_t wc = _utf8_get_char (in);
 
400
 
 
401
        if (wc < 0x10000) {
 
402
            str16[i++] = wc;
 
403
        } else {
 
404
            str16[i++] = (wc - 0x10000) / 0x400 + 0xd800;
 
405
            str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
 
406
        }
 
407
 
 
408
        in = UTF8_NEXT_CHAR (in);
 
409
    }
 
410
 
 
411
    str16[i] = 0;
 
412
 
 
413
    *result = str16;
 
414
    if (items_written)
 
415
        *items_written = n16;
 
416
 
 
417
    return CAIRO_STATUS_SUCCESS;
 
418
}
 
419
#endif