Branch data Line data Source code
1 : : /*
2 : : Copyright (c) 2010-2014 Jeremiah Martell
3 : : All rights reserved.
4 : :
5 : : Redistribution and use in source and binary forms, with or without modification,
6 : : are permitted provided that the following conditions are met:
7 : :
8 : : - Redistributions of source code must retain the above copyright notice,
9 : : this list of conditions and the following disclaimer.
10 : : - Redistributions in binary form must reproduce the above copyright notice,
11 : : this list of conditions and the following disclaimer in the documentation
12 : : and/or other materials provided with the distribution.
13 : : - Neither the name of Jeremiah Martell nor the name of GeekHorse nor the
14 : : name of Trot nor the names of its contributors may be used to endorse or
15 : : promote products derived from this software without specific prior written
16 : : permission.
17 : :
18 : : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 : : ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 : : WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 : : DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 : : ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 : : (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 : : LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 : : ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 : : SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : /******************************************************************************/
31 : : /*!
32 : : \file
33 : : Unicode conversion functions.
34 : :
35 : : Reference:
36 : : http://unicode.org
37 : : The Unicode Standard, Version 6.0
38 : : Chapter 3, Conformance
39 : : Table 3-6. UTF-8 Bit Distribution
40 : : Table 3-7. Well-Formed UTF-8 Byte Sequences
41 : : */
42 : : #define TROT_FILE_NUMBER 4
43 : :
44 : : /******************************************************************************/
45 : : #include "trot.h"
46 : : #include "trotInternal.h"
47 : :
48 : : /******************************************************************************/
49 : : /*!
50 : : \brief Decodes a list of utf8 bytes to characters.
51 : : \param[in] lBytes List of bytes.
52 : : \param[in] lCharacters List to append decoded characters.
53 : : \return TROT_RC
54 : :
55 : : */
56 : 1112554 : TROT_RC trotUtf8ToCharacters( TrotList *lBytes, TrotList *lCharacters )
57 : : {
58 : : /* DATA */
59 : 1112554 : TROT_RC rc = TROT_RC_SUCCESS;
60 : :
61 : 1112554 : TROT_INT numberOfBytes = 0;
62 : 1112554 : TROT_INT index = 1;
63 : :
64 : 1112554 : TROT_INT byte1 = 0;
65 : 1112554 : TROT_INT byte2 = 0;
66 : 1112554 : TROT_INT byte3 = 0;
67 : 1112554 : TROT_INT byte4 = 0;
68 : 1112554 : TROT_INT character = 0;
69 : :
70 : :
71 : : /* PRECOND */
72 [ + + ]: 1112554 : ERR_IF( lBytes == NULL, TROT_RC_ERROR_PRECOND );
73 [ + + ]: 1112553 : ERR_IF( lCharacters == NULL, TROT_RC_ERROR_PRECOND );
74 : :
75 : :
76 : : /* CODE */
77 : : /* get numberOfBytes */
78 : 1112552 : rc = trotListGetCount( lBytes, &numberOfBytes );
79 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
80 : :
81 : : /* go through bytes */
82 : 1112552 : index = 1;
83 [ + + ]: 2253766 : while ( index <= numberOfBytes )
84 : : {
85 : : /* get first byte */
86 : 1141302 : rc = trotListGetInt( lBytes, index, &byte1 );
87 [ + + ]: 1141302 : ERR_IF_PASSTHROUGH;
88 : :
89 : : /* one byte sequence */
90 [ + + ][ + + ]: 1141301 : if ( byte1 >= 0x00 && byte1 <= 0x7F )
91 : : {
92 : : /* append character */
93 : 8006 : character = byte1;
94 : 8006 : rc = trotListAppendInt( lCharacters, character );
95 [ + + ]: 8006 : ERR_IF_PASSTHROUGH;
96 : :
97 : : /* *** */
98 : 7990 : index += 1;
99 : 7990 : continue;
100 : : }
101 : :
102 : : /* two byte sequence */
103 [ + + ][ + + ]: 1133295 : if ( byte1 >= 0xC2 && byte1 <= 0xDF )
104 : : {
105 : : /* get second byte */
106 : 9035 : index += 1;
107 : 9035 : rc = trotListGetInt( lBytes, index, &byte2 );
108 [ + + ]: 9035 : ERR_IF_PASSTHROUGH;
109 : :
110 : : /* validate second byte */
111 [ + + ][ + + ]: 9034 : if ( ! ( byte2 >= 0x80 && byte2 <= 0xBF ) )
112 : : {
113 : 2 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
114 : : }
115 : :
116 : : /* append character */
117 : 9032 : character = ((byte1 & 0x1F) << 6) | (byte2 & 0x3F);
118 : 9032 : rc = trotListAppendInt( lCharacters, character );
119 [ + + ]: 9032 : ERR_IF_PASSTHROUGH;
120 : :
121 : : /* *** */
122 : 9024 : index += 1;
123 : 9024 : continue;
124 : : }
125 : :
126 : : /* three byte sequence */
127 [ + + ][ + + ]: 1124260 : if ( byte1 >= 0xE0 && byte1 <= 0xEF )
128 : : {
129 : : /* get second byte */
130 : 68562 : index += 1;
131 : 68562 : rc = trotListGetInt( lBytes, index, &byte2 );
132 [ + + ]: 68562 : ERR_IF_PASSTHROUGH;
133 : :
134 : : /* validate second byte */
135 [ + + ]: 68561 : if ( byte1 == 0xE0 )
136 : : {
137 [ + + ][ + + ]: 2053 : if ( ! ( byte2 >= 0xA0 && byte2 <= 0xBF ) )
138 : : {
139 : 2 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
140 : : }
141 : : }
142 [ + + ]: 66508 : else if ( byte1 <= 0xEC )
143 : : {
144 [ + + ][ + + ]: 56260 : if ( ! ( byte2 >= 0x80 && byte2 <= 0xBF ) )
145 : : {
146 : 2 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
147 : : }
148 : : }
149 [ + + ]: 10248 : else if ( byte1 == 0xED )
150 : : {
151 [ + + ][ + + ]: 2052 : if ( ! ( byte2 >= 0x80 && byte2 <= 0x9F ) )
152 : : {
153 : 2 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
154 : : }
155 : : }
156 : : else
157 : : {
158 [ + + ][ + + ]: 8196 : if ( ! ( byte2 >= 0x80 && byte2 <= 0xBF ) )
159 : : {
160 : 2 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
161 : : }
162 : : }
163 : :
164 : : /* get third byte */
165 : 68553 : index += 1;
166 : 68553 : rc = trotListGetInt( lBytes, index, &byte3 );
167 [ + + ]: 68553 : ERR_IF_PASSTHROUGH;
168 : :
169 : : /* validate third byte */
170 [ + + ][ + + ]: 68552 : if ( ! ( byte3 >= 0x80 && byte3 <= 0xBF ) )
171 : : {
172 : 8 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte3 );
173 : : }
174 : :
175 : : /* append character */
176 : 68544 : character = ((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F);
177 : 68544 : rc = trotListAppendInt( lCharacters, character );
178 [ + + ]: 68544 : ERR_IF_PASSTHROUGH;
179 : :
180 : : /* *** */
181 : 68536 : index += 1;
182 : 68536 : continue;
183 : : }
184 : :
185 : : /* four byte sequence */
186 [ + + ][ + + ]: 1055698 : if ( byte1 >= 0xF0 && byte1 <= 0xF4 )
187 : : {
188 : : /* get second byte */
189 : 1055693 : index += 1;
190 : 1055693 : rc = trotListGetInt( lBytes, index, &byte2 );
191 [ + + ]: 1055693 : ERR_IF_PASSTHROUGH;
192 : :
193 : : /* validate second byte */
194 [ + + ]: 1055692 : if ( byte1 == 0xF0 )
195 : : {
196 [ + + ][ + + ]: 196616 : if ( ! ( byte2 >= 0x90 && byte2 <= 0xBF ) )
197 : : {
198 : 6 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
199 : : }
200 : : }
201 [ + + ]: 859076 : else if ( byte1 <= 0xF3 )
202 : : {
203 [ + + ][ + + ]: 786438 : if ( ! ( byte2 >= 0x80 && byte2 <= 0xBF ) )
204 : : {
205 : 2 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
206 : : }
207 : : }
208 : : else
209 : : {
210 [ + + ][ + + ]: 72638 : if ( ! ( byte2 >= 0x80 && byte2 <= 0x8F ) )
211 : : {
212 : 2 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte2 );
213 : : }
214 : : }
215 : :
216 : : /* get third byte */
217 : 1055682 : index += 1;
218 : 1055682 : rc = trotListGetInt( lBytes, index, &byte3 );
219 [ + + ]: 1055682 : ERR_IF_PASSTHROUGH;
220 : :
221 : : /* validate third byte */
222 [ + + ][ + + ]: 1055681 : if ( ! ( byte3 >= 0x80 && byte3 <= 0xBF ) )
223 : : {
224 : 4 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte3 );
225 : : }
226 : :
227 : : /* get fourth byte */
228 : 1055677 : index += 1;
229 : 1055677 : rc = trotListGetInt( lBytes, index, &byte4 );
230 [ + + ]: 1055677 : ERR_IF_PASSTHROUGH;
231 : :
232 : : /* validate fourth byte */
233 [ + + ][ + + ]: 1055676 : if ( ! ( byte4 >= 0x80 && byte4 <= 0xBF ) )
234 : : {
235 : 4 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte4 );
236 : : }
237 : :
238 : : /* append character */
239 : 1055672 : character = ((byte1 & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F);
240 : 1055672 : rc = trotListAppendInt( lCharacters, character );
241 [ + + ]: 1055672 : ERR_IF_PASSTHROUGH;
242 : :
243 : : /* *** */
244 : 1055664 : index += 1;
245 : 1055664 : continue;
246 : : }
247 : :
248 : : /* invalid first byte */
249 : 5 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, byte1 );
250 : : }
251 : :
252 : :
253 : : /* CLEANUP */
254 : : cleanup:
255 : :
256 : 1112554 : return rc;
257 : : }
258 : :
259 : : /******************************************************************************/
260 : : /*!
261 : : \brief Encodes a list of characters to utf8 bytes.
262 : : \param[in] lCharacters List of characters.
263 : : \param[in] lBytes List to append bytes to.
264 : : \return TROT_RC
265 : : */
266 : 1112599 : TROT_RC trotCharactersToUtf8( TrotList *lCharacters, TrotList *lBytes )
267 : : {
268 : : /* DATA */
269 : 1112599 : TROT_RC rc = TROT_RC_SUCCESS;
270 : :
271 : 1112599 : TROT_INT numberOfCharacters = 0;
272 : 1112599 : TROT_INT index = 1;
273 : :
274 : 1112599 : TROT_INT character = 0;
275 : 1112599 : TROT_INT byte1 = 0;
276 : 1112599 : TROT_INT byte2 = 0;
277 : 1112599 : TROT_INT byte3 = 0;
278 : 1112599 : TROT_INT byte4 = 0;
279 : :
280 : :
281 : : /* PRECOND */
282 [ + + ]: 1112599 : ERR_IF( lCharacters == NULL, TROT_RC_ERROR_PRECOND );
283 [ + + ]: 1112598 : ERR_IF( lBytes == NULL, TROT_RC_ERROR_PRECOND );
284 : :
285 : :
286 : : /* CODE */
287 : : /* get numberOfCharacters */
288 : 1112597 : rc = trotListGetCount( lCharacters, &numberOfCharacters );
289 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
290 : :
291 : : /* go through characters */
292 : 1112597 : index = 1;
293 [ + + ]: 2258303 : while ( index <= numberOfCharacters )
294 : : {
295 : : /* get character */
296 : 1145799 : rc = trotListGetInt( lCharacters, index, &character );
297 [ + + ]: 1145799 : ERR_IF_PASSTHROUGH;
298 : :
299 : : /* 1 byte: 0x00 - 0x7F */
300 [ + + ][ + + ]: 1145798 : if ( character >= 0x00 && character <= 0x7F )
301 : : {
302 : : /* setup bytes */
303 : 9314 : byte1 = character;
304 : :
305 : : /* append bytes */
306 : 9314 : rc = trotListAppendInt( lBytes, byte1 );
307 [ + + ]: 9314 : ERR_IF_PASSTHROUGH;
308 : : }
309 : : /* 2 byte: 0x80 - 0x7FF */
310 [ + + ][ + + ]: 1136484 : else if ( character >= 0x80 && character <= 0x7FF )
311 : : {
312 : : /* setup bytes */
313 : 10120 : byte1 = ( ( character >> 6 ) & 0x1F ) | 0xC0;
314 : 10120 : byte2 = ( ( character ) & 0x3F ) | 0x80;
315 : :
316 : : /* append bytes */
317 : 10120 : rc = trotListAppendInt( lBytes, byte1 );
318 [ + + ]: 10120 : ERR_IF_PASSTHROUGH;
319 : 10112 : rc = trotListAppendInt( lBytes, byte2 );
320 [ + + ]: 10112 : ERR_IF_PASSTHROUGH;
321 : : }
322 : : /* 3 byte: 0x800 - 0xD7FF, 0xE000 - 0xFFFF */
323 [ + + ]: 1126364 : else if (
324 [ + + ]: 1126363 : ( character >= 0x800 && character <= 0xD7FF )
325 [ + + ][ + + ]: 1064932 : || ( character >= 0xE000 && character <= 0xFFFF )
326 : : )
327 : : {
328 : : /* setup bytes */
329 : 69624 : byte1 = ( ( character >> 12 ) & 0x0F ) | 0xE0;
330 : 69624 : byte2 = ( ( character >> 6 ) & 0x3F ) | 0x80;
331 : 69624 : byte3 = ( ( character ) & 0x3F ) | 0x80;
332 : :
333 : : /* append bytes */
334 : 69624 : rc = trotListAppendInt( lBytes, byte1 );
335 [ + + ]: 69624 : ERR_IF_PASSTHROUGH;
336 : 69616 : rc = trotListAppendInt( lBytes, byte2 );
337 [ + + ]: 69616 : ERR_IF_PASSTHROUGH;
338 : 69608 : rc = trotListAppendInt( lBytes, byte3 );
339 [ + + ]: 69608 : ERR_IF_PASSTHROUGH;
340 : : }
341 : : /* 4 byte: 0x10000 - 0x10FFFF */
342 [ + + ][ + + ]: 1056740 : else if ( character >= 0x10000 && character <= 0x10FFFF )
343 : : {
344 : : /* setup bytes */
345 : 1056736 : byte1 = ( ( character >> 18 ) & 0x07 ) | 0xF0;
346 : 1056736 : byte2 = ( ( character >> 12 ) & 0x3F ) | 0x80;
347 : 1056736 : byte3 = ( ( character >> 6 ) & 0x3F ) | 0x80;
348 : 1056736 : byte4 = ( ( character ) & 0x3F ) | 0x80;
349 : :
350 : : /* append bytes */
351 : 1056736 : rc = trotListAppendInt( lBytes, byte1 );
352 [ + + ]: 1056736 : ERR_IF_PASSTHROUGH;
353 : 1056728 : rc = trotListAppendInt( lBytes, byte2 );
354 [ + + ]: 1056728 : ERR_IF_PASSTHROUGH;
355 : 1056720 : rc = trotListAppendInt( lBytes, byte3 );
356 [ + + ]: 1056720 : ERR_IF_PASSTHROUGH;
357 : 1056712 : rc = trotListAppendInt( lBytes, byte4 );
358 [ + + ]: 1056712 : ERR_IF_PASSTHROUGH;
359 : : }
360 : : else
361 : : {
362 : 4 : ERR_IF_1( 1, TROT_RC_ERROR_UNICODE, character );
363 : : }
364 : :
365 : : /* *** */
366 : 1145706 : index += 1;
367 : : }
368 : :
369 : :
370 : : /* CLEANUP */
371 : : cleanup:
372 : :
373 : 1112599 : return rc;
374 : : }
375 : :
376 : : /******************************************************************************/
377 : : /*!
378 : : \brief Is a character a whitespace character?
379 : : \param[in] character The character to check.
380 : : \return s32 1 if whitespace, 0 if not.
381 : : */
382 : 2187188 : s32 trotUnicodeIsWhitespace( TROT_INT character )
383 : : {
384 [ + + ]: 2187188 : if ( character == '\t' /* horizontal tab */
385 [ + + ]: 2187133 : || character == '\n' /* newline */
386 [ + + ]: 2187040 : || character == 0x0B /* vertical tab */
387 [ + + ]: 2187039 : || character == 0x0C /* form feed */
388 [ + + ]: 2187038 : || character == '\r' /* carriage return */
389 [ + + ]: 2187037 : || character == ' ' /* space */
390 [ + + ]: 1263780 : || character == 0x85 /* next line */
391 [ + + ]: 1263779 : || character == 0xA0 /* no break space */
392 [ + + ]: 1263778 : || character == 0x1680 /* ogham space mark */
393 [ + + ]: 1263777 : || character == 0x180E /* mongolian vowel separator */
394 [ + + ]: 1263776 : || character == 0x2000 /* en quad */
395 [ + + ]: 1263775 : || character == 0x2001 /* em quad */
396 [ + + ]: 1263774 : || character == 0x2002 /* en space */
397 [ + + ]: 1263773 : || character == 0x2003 /* em space */
398 [ + + ]: 1263772 : || character == 0x2004 /* three-per-em space */
399 [ + + ]: 1263771 : || character == 0x2005 /* four-per-em space */
400 [ + + ]: 1263770 : || character == 0x2006 /* six-per-em space */
401 [ + + ]: 1263769 : || character == 0x2007 /* figure space */
402 [ + + ]: 1263768 : || character == 0x2008 /* punctuation space */
403 [ + + ]: 1263767 : || character == 0x2009 /* thin space */
404 [ + + ]: 1263766 : || character == 0x200A /* hair space */
405 [ + + ]: 1263765 : || character == 0x2028 /* line separator */
406 [ + + ]: 1263764 : || character == 0x2029 /* paragraph separator */
407 [ + + ]: 1263763 : || character == 0x202F /* narrow no-break space */
408 [ + + ]: 1263762 : || character == 0x205F /* medium mathematical space */
409 [ + + ]: 1263761 : || character == 0x3000 /* ideographic space */
410 : : )
411 : : {
412 : 923428 : return 1;
413 : : }
414 : :
415 : 2187188 : return 0;
416 : : }
417 : :
|