svn merge ^/trunk/blender -r41100:41150
[blender.git] / source / blender / blenlib / intern / string_utf8.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2011 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Campbell Barton.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29  /** \file blender/blenlib/intern/string_utf8.c
30  *  \ingroup bli
31  */
32
33 #include <string.h>
34 #include <wchar.h>
35 #include <wctype.h>
36
37 #include "BLI_string.h"
38
39 /* from libswish3, originally called u8_isvalid(),
40  * modified to return the index of the bad character (byte index not utf).
41  * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
42
43 /* based on the valid_utf8 routine from the PCRE library by Philip Hazel
44
45    length is in bytes, since without knowing whether the string is valid
46    it's hard to know how many characters there are! */
47
48 static const char trailingBytesForUTF8[256] = {
49         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
50         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
51         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
52         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
53         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
54         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
55         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,
56         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
57 };
58
59 int BLI_utf8_invalid_byte(const char *str, int length)
60 {
61         const unsigned char *p, *pend = (unsigned char*)str + length;
62         unsigned char c;
63         int ab;
64
65         for (p = (unsigned char*)str; p < pend; p++) {
66                 c = *p;
67                 if (c < 128)
68                         continue;
69                 if ((c & 0xc0) != 0xc0)
70                         goto utf8_error;
71                 ab = trailingBytesForUTF8[c];
72                 if (length < ab)
73                         goto utf8_error;
74                 length -= ab;
75
76                 p++;
77                 /* Check top bits in the second byte */
78                 if ((*p & 0xc0) != 0x80)
79                         goto utf8_error;
80
81                 /* Check for overlong sequences for each different length */
82                 switch (ab) {
83                         /* Check for xx00 000x */
84                 case 1:
85                         if ((c & 0x3e) == 0) goto utf8_error;
86                         continue;   /* We know there aren't any more bytes to check */
87
88                         /* Check for 1110 0000, xx0x xxxx */
89                 case 2:
90                         if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
91                         break;
92
93                         /* Check for 1111 0000, xx00 xxxx */
94                 case 3:
95                         if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
96                         break;
97
98                         /* Check for 1111 1000, xx00 0xxx */
99                 case 4:
100                         if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
101                         break;
102
103                         /* Check for leading 0xfe or 0xff,
104                            and then for 1111 1100, xx00 00xx */
105                 case 5:
106                         if (c == 0xfe || c == 0xff ||
107                                 (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
108                         break;
109                 }
110
111                 /* Check for valid bytes after the 2nd, if any; all must start 10 */
112                 while (--ab > 0) {
113                         if ((*(p+1) & 0xc0) != 0x80) goto utf8_error;
114                         p++; /* do this after so we get usable offset - campbell */
115                 }
116         }
117
118         return -1;
119
120 utf8_error:
121
122         return (int)((char *)p - (char *)str) - 1;
123 }
124
125 int BLI_utf8_invalid_strip(char *str, int length)
126 {
127         int bad_char, tot= 0;
128
129         while((bad_char= BLI_utf8_invalid_byte(str, length)) != -1) {
130                 str += bad_char;
131                 length -= bad_char;
132
133                 if(length == 0) {
134                         /* last character bad, strip it */
135                         *str= '\0';
136                         tot++;
137                         break;
138                 }
139                 else {
140                         /* strip, keep looking */
141                         memmove(str, str + 1, length);
142                         tot++;
143                 }
144         }
145
146         return tot;
147 }
148
149
150 /* compatible with BLI_strncpy, but esnure no partial utf8 chars */
151
152 /* array copied from glib's gutf8.c,
153  * note: this looks to be at odd's with 'trailingBytesForUTF8',
154  * need to find out what gives here! - campbell */
155 static const size_t utf8_skip_data[256] = {
156     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,
157     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,
158     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,
159     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,
160     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,
161     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,
162     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,
163     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
164 };
165
166 char *BLI_strncpy_utf8(char *dst, const char *src, size_t maxncpy)
167 {
168         char *dst_r= dst;
169         size_t utf8_size;
170
171         /* note: currently we dont attempt to deal with invalid utf8 chars */
172
173         while(*src != '\0' && (utf8_size= utf8_skip_data[*src]) < maxncpy) {
174                 maxncpy -= utf8_size;
175                 switch(utf8_size) {
176                         case 6: *dst ++ = *src ++;
177                         case 5: *dst ++ = *src ++;
178                         case 4: *dst ++ = *src ++;
179                         case 3: *dst ++ = *src ++;
180                         case 2: *dst ++ = *src ++;
181                         case 1: *dst ++ = *src ++;
182                 }
183         }
184         *dst= '\0';
185         return dst_r;
186 }
187
188
189 /* --------------------------------------------------------------------------*/
190 /* wchar_t / utf8 functions  */
191
192 /* UTF-8 <-> wchar transformations */
193 static size_t chtoutf8(const unsigned long c, char o[4])
194 {
195         // Variables and initialization
196 /*      memset(o, 0, 4);        */
197
198         // Create the utf-8 string
199         if (c < 0x80) {
200                 o[0] = (char) c;
201                 return 1;
202         }
203         else if (c < 0x800) {
204                 o[0] = (0xC0 | (c>>6));
205                 o[1] = (0x80 | (c & 0x3f));
206                 return 2;
207         }
208         else if (c < 0x10000) {
209                 o[0] = (0xe0 | (c >> 12));
210                 o[1] = (0x80 | (c >>6 & 0x3f));
211                 o[2] = (0x80 | (c & 0x3f));
212                 return 3;
213         }
214         else if (c < 0x200000) {
215                 o[0] = (0xf0 | (c>>18));
216                 o[1] = (0x80 | (c >>12 & 0x3f));
217                 o[2] = (0x80 | (c >> 6 & 0x3f));
218                 o[3] = (0x80 | (c & 0x3f));
219                 return 4;
220         }
221
222         /* should we assert here? */
223         return 0;
224 }
225
226 size_t BLI_strncpy_wchar_as_utf8(char *dst, const wchar_t *src, const size_t maxcpy)
227 {
228         size_t len = 0;
229         while(*src && len < maxcpy) { /* XXX can still run over the buffer because utf8 size isnt known :| */
230                 len += chtoutf8(*src++, dst+len);
231         }
232
233         dst[len]= '\0';
234
235         return len;
236 }
237
238 /* wchar len in utf8 */
239 size_t BLI_wstrlen_utf8(const wchar_t *src)
240 {
241         char ch_dummy[4];
242         size_t len = 0;
243
244         while(*src) {
245                 len += chtoutf8(*src++, ch_dummy);
246         }
247
248         return len;
249 }
250
251 // utf8slen
252 size_t BLI_strlen_utf8(const char *strc)
253 {
254         int len=0;
255
256         while(*strc) {
257                 if ((*strc & 0xe0) == 0xc0) {
258                         if((strc[1] & 0x80) && (strc[1] & 0x40) == 0x00)
259                                 strc++;
260                 } else if ((*strc & 0xf0) == 0xe0) {
261                         if((strc[1] & strc[2] & 0x80) && ((strc[1] | strc[2]) & 0x40) == 0x00)
262                                 strc += 2;
263                 } else if ((*strc & 0xf8) == 0xf0) {
264                         if((strc[1] & strc[2] & strc[3] & 0x80) && ((strc[1] | strc[2] | strc[3]) & 0x40) == 0x00)
265                                 strc += 3;
266                 }
267
268                 strc++;
269                 len++;
270         }
271
272         return len;
273 }
274
275
276 /* Converts Unicode to wchar
277
278 According to RFC 3629 "UTF-8, a transformation format of ISO 10646"
279 (http://tools.ietf.org/html/rfc3629), the valid UTF-8 encoding are:
280
281   Char. number range  |        UTF-8 octet sequence
282           (hexadecimal)    |              (binary)
283    --------------------+---------------------------------------------
284    0000 0000-0000 007F | 0xxxxxxx
285    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
286    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
287    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
288
289 If the encoding incidated by the first character is incorrect (because the
290 1 to 3 following characters do not match 10xxxxxx), the output is a '?' and
291 only a single input character is consumed.
292
293 */
294
295 size_t BLI_strncpy_wchar_from_utf8(wchar_t *dst_w, const char *src_c, const size_t maxcpy)
296 {
297         int len=0;
298
299         if(dst_w==NULL || src_c==NULL) return(0);
300
301         while(*src_c && len < maxcpy) {
302                 if ((*src_c & 0xe0) == 0xc0) {
303                         if((src_c[1] & 0x80) && (src_c[1] & 0x40) == 0x00) {
304                                 *dst_w=((src_c[0] &0x1f)<<6) | (src_c[1]&0x3f);
305                                 src_c++;
306                         } else {
307                                 *dst_w = '?';
308                         }
309                 } else if ((*src_c & 0xf0) == 0xe0) {
310                         if((src_c[1] & src_c[2] & 0x80) && ((src_c[1] | src_c[2]) & 0x40) == 0x00) {
311                                 *dst_w=((src_c[0] & 0x0f)<<12) | ((src_c[1]&0x3f)<<6) | (src_c[2]&0x3f);
312                                 src_c += 2;
313                         } else {
314                                 *dst_w = '?';
315                         }
316                 } else if ((*src_c & 0xf8) == 0xf0) {
317                         if((src_c[1] & src_c[2] & src_c[3] & 0x80) && ((src_c[1] | src_c[2] | src_c[3]) & 0x40) == 0x00) {
318                                 *dst_w=((src_c[0] & 0x07)<<18) | ((src_c[1]&0x1f)<<12) | ((src_c[2]&0x3f)<<6) | (src_c[3]&0x3f);
319                                 src_c += 3;
320                         } else {
321                                 *dst_w = '?';
322                         }
323                 } else {
324                         *dst_w=(src_c[0] & 0x7f);
325                 }
326
327                 src_c++;
328                 dst_w++;
329                 len++;
330         }
331         return len;
332 }
333
334 /* end wchar_t / utf8 functions  */
335 /* --------------------------------------------------------------------------*/
336
337
338
339
340
341 /* copied from glib */
342 /**
343  * g_utf8_find_prev_char:
344  * @str: pointer to the beginning of a UTF-8 encoded string
345  * @p: pointer to some position within @str
346  *
347  * Given a position @p with a UTF-8 encoded string @str, find the start
348  * of the previous UTF-8 character starting before @p. Returns %NULL if no
349  * UTF-8 characters are present in @str before @p.
350  *
351  * @p does not have to be at the beginning of a UTF-8 character. No check
352  * is made to see if the character found is actually valid other than
353  * it starts with an appropriate byte.
354  *
355  * Return value: a pointer to the found character or %NULL.
356  **/
357 char * BLI_str_find_prev_char_utf8(const char *str, const char *p)
358 {
359         for (--p; p >= str; --p) {
360                 if ((*p & 0xc0) != 0x80) {
361                         return (char *)p;
362                 }
363         }
364         return NULL;
365 }
366
367 /**
368  * g_utf8_find_next_char:
369  * @p: a pointer to a position within a UTF-8 encoded string
370  * @end: a pointer to the byte following the end of the string,
371  * or %NULL to indicate that the string is nul-terminated.
372  *
373  * Finds the start of the next UTF-8 character in the string after @p.
374  *
375  * @p does not have to be at the beginning of a UTF-8 character. No check
376  * is made to see if the character found is actually valid other than
377  * it starts with an appropriate byte.
378  *
379  * Return value: a pointer to the found character or %NULL
380  **/
381 char *BLI_str_find_next_char_utf8(const char *p, const char *end)
382 {
383         if (*p) {
384                 if (end) {
385                         for (++p; p < end && (*p & 0xc0) == 0x80; ++p) {
386                                 /* do nothing */
387                         }
388                 }
389                 else {
390                         for (++p; (*p & 0xc0) == 0x80; ++p) {
391                                 /* do nothing */
392                         }
393                 }
394         }
395         return (p == end) ? NULL : (char *)p;
396 }
397
398 /**
399  * g_utf8_prev_char:
400  * @p: a pointer to a position within a UTF-8 encoded string
401  *
402  * Finds the previous UTF-8 character in the string before @p.
403  *
404  * @p does not have to be at the beginning of a UTF-8 character. No check
405  * is made to see if the character found is actually valid other than
406  * it starts with an appropriate byte. If @p might be the first
407  * character of the string, you must use g_utf8_find_prev_char() instead.
408  *
409  * Return value: a pointer to the found character.
410  **/
411 char *BLI_str_prev_char_utf8(const char *p)
412 {
413         while (1) {
414                 p--;
415                 if ((*p & 0xc0) != 0x80) {
416                         return (char *)p;
417                 }
418         }
419 }
420 /* end glib copy */