xref: /unit/src/nxt_utf8.c (revision 0)
1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru #include <nxt_main.h>
8*0Sigor@sysoev.ru 
9*0Sigor@sysoev.ru /*
10*0Sigor@sysoev.ru  * The nxt_unicode_lowcase.h file is the auto-generated file from
11*0Sigor@sysoev.ru  * the CaseFolding-6.3.0.txt file provided by Unicode, Inc.:
12*0Sigor@sysoev.ru  *
13*0Sigor@sysoev.ru  *   ./lib/src/nxt_unicode_lowcase.pl CaseFolding-6.3.0.txt
14*0Sigor@sysoev.ru  *
15*0Sigor@sysoev.ru  * This file should be copied to system specific nxt_unicode_SYSTEM_lowcase.h
16*0Sigor@sysoev.ru  * file and utf8_file_name_test should be built with this file.
17*0Sigor@sysoev.ru  * Then a correct system specific file should be generated:
18*0Sigor@sysoev.ru  *
19*0Sigor@sysoev.ru  *   ./build/utf8_file_name_test | ./lib/src/nxt_unicode_lowcase.pl
20*0Sigor@sysoev.ru  *
21*0Sigor@sysoev.ru  * Only common and simple case foldings are supported.  Full case foldings
22*0Sigor@sysoev.ru  * is not supported.  Combined characters are also not supported.
23*0Sigor@sysoev.ru  */
24*0Sigor@sysoev.ru 
25*0Sigor@sysoev.ru #if (NXT_MACOSX)
26*0Sigor@sysoev.ru #include <nxt_unicode_macosx_lowcase.h>
27*0Sigor@sysoev.ru 
28*0Sigor@sysoev.ru #else
29*0Sigor@sysoev.ru #include <nxt_unicode_lowcase.h>
30*0Sigor@sysoev.ru #endif
31*0Sigor@sysoev.ru 
32*0Sigor@sysoev.ru 
33*0Sigor@sysoev.ru u_char *
34*0Sigor@sysoev.ru nxt_utf8_encode(u_char *p, uint32_t u)
35*0Sigor@sysoev.ru {
36*0Sigor@sysoev.ru     if (u < 0x80) {
37*0Sigor@sysoev.ru         *p++ = (u_char) (u & 0xff);
38*0Sigor@sysoev.ru         return p;
39*0Sigor@sysoev.ru     }
40*0Sigor@sysoev.ru 
41*0Sigor@sysoev.ru     if (u < 0x0800) {
42*0Sigor@sysoev.ru         *p++ = (u_char) (( u >> 6)          | 0xc0);
43*0Sigor@sysoev.ru         *p++ = (u_char) (( u        & 0x3f) | 0x80);
44*0Sigor@sysoev.ru         return p;
45*0Sigor@sysoev.ru     }
46*0Sigor@sysoev.ru 
47*0Sigor@sysoev.ru     if (u < 0x10000) {
48*0Sigor@sysoev.ru         *p++ = (u_char) ( (u >> 12)         | 0xe0);
49*0Sigor@sysoev.ru         *p++ = (u_char) (((u >>  6) & 0x3f) | 0x80);
50*0Sigor@sysoev.ru         *p++ = (u_char) (( u        & 0x3f) | 0x80);
51*0Sigor@sysoev.ru         return p;
52*0Sigor@sysoev.ru     }
53*0Sigor@sysoev.ru 
54*0Sigor@sysoev.ru     if (u < 0x110000) {
55*0Sigor@sysoev.ru         *p++ = (u_char) ( (u >> 18)         | 0xf0);
56*0Sigor@sysoev.ru         *p++ = (u_char) (((u >> 12) & 0x3f) | 0x80);
57*0Sigor@sysoev.ru         *p++ = (u_char) (((u >>  6) & 0x3f) | 0x80);
58*0Sigor@sysoev.ru         *p++ = (u_char) (( u        & 0x3f) | 0x80);
59*0Sigor@sysoev.ru         return p;
60*0Sigor@sysoev.ru     }
61*0Sigor@sysoev.ru 
62*0Sigor@sysoev.ru     return NULL;
63*0Sigor@sysoev.ru }
64*0Sigor@sysoev.ru 
65*0Sigor@sysoev.ru 
66*0Sigor@sysoev.ru /*
67*0Sigor@sysoev.ru  * nxt_utf8_decode() decodes UTF-8 sequences and returns a valid
68*0Sigor@sysoev.ru  * character 0x00 - 0x10ffff, or 0xffffffff for invalid or overlong
69*0Sigor@sysoev.ru  * UTF-8 sequence.
70*0Sigor@sysoev.ru  */
71*0Sigor@sysoev.ru 
72*0Sigor@sysoev.ru uint32_t
73*0Sigor@sysoev.ru nxt_utf8_decode(const u_char **start, const u_char *end)
74*0Sigor@sysoev.ru {
75*0Sigor@sysoev.ru     uint32_t  u;
76*0Sigor@sysoev.ru 
77*0Sigor@sysoev.ru     u = (uint32_t) **start;
78*0Sigor@sysoev.ru 
79*0Sigor@sysoev.ru     if (u < 0x80) {
80*0Sigor@sysoev.ru         (*start)++;
81*0Sigor@sysoev.ru         return u;
82*0Sigor@sysoev.ru     }
83*0Sigor@sysoev.ru 
84*0Sigor@sysoev.ru     return nxt_utf8_decode2(start, end);
85*0Sigor@sysoev.ru }
86*0Sigor@sysoev.ru 
87*0Sigor@sysoev.ru 
88*0Sigor@sysoev.ru /*
89*0Sigor@sysoev.ru  * nxt_utf8_decode2() decodes two and more bytes UTF-8 sequences only
90*0Sigor@sysoev.ru  * and returns a valid character 0x80 - 0x10ffff, or 0xffffffff for
91*0Sigor@sysoev.ru  * invalid or overlong UTF-8 sequence.
92*0Sigor@sysoev.ru  */
93*0Sigor@sysoev.ru 
94*0Sigor@sysoev.ru uint32_t
95*0Sigor@sysoev.ru nxt_utf8_decode2(const u_char **start, const u_char *end)
96*0Sigor@sysoev.ru {
97*0Sigor@sysoev.ru     u_char        c;
98*0Sigor@sysoev.ru     size_t        n;
99*0Sigor@sysoev.ru     uint32_t      u, overlong;
100*0Sigor@sysoev.ru     const u_char  *p;
101*0Sigor@sysoev.ru 
102*0Sigor@sysoev.ru     p = *start;
103*0Sigor@sysoev.ru     u = (uint32_t) *p;
104*0Sigor@sysoev.ru 
105*0Sigor@sysoev.ru     if (u >= 0xe0) {
106*0Sigor@sysoev.ru 
107*0Sigor@sysoev.ru         if (u >= 0xf0) {
108*0Sigor@sysoev.ru 
109*0Sigor@sysoev.ru             if (nxt_slow_path(u > 0xf4)) {
110*0Sigor@sysoev.ru                 /*
111*0Sigor@sysoev.ru                  * The maximum valid Unicode character is 0x10ffff
112*0Sigor@sysoev.ru                  * which is encoded as 0xf4 0x8f 0xbf 0xbf.
113*0Sigor@sysoev.ru                  */
114*0Sigor@sysoev.ru                 return 0xffffffff;
115*0Sigor@sysoev.ru             }
116*0Sigor@sysoev.ru 
117*0Sigor@sysoev.ru             u &= 0x07;
118*0Sigor@sysoev.ru             overlong = 0x00ffff;
119*0Sigor@sysoev.ru             n = 3;
120*0Sigor@sysoev.ru 
121*0Sigor@sysoev.ru         } else {
122*0Sigor@sysoev.ru             u &= 0x0f;
123*0Sigor@sysoev.ru             overlong = 0x07ff;
124*0Sigor@sysoev.ru             n = 2;
125*0Sigor@sysoev.ru         }
126*0Sigor@sysoev.ru 
127*0Sigor@sysoev.ru     } else if (u >= 0xc2) {
128*0Sigor@sysoev.ru 
129*0Sigor@sysoev.ru         /* 0x80 is encoded as 0xc2 0x80. */
130*0Sigor@sysoev.ru 
131*0Sigor@sysoev.ru         u &= 0x1f;
132*0Sigor@sysoev.ru         overlong = 0x007f;
133*0Sigor@sysoev.ru         n = 1;
134*0Sigor@sysoev.ru 
135*0Sigor@sysoev.ru     } else {
136*0Sigor@sysoev.ru         /* u <= 0xc2 */
137*0Sigor@sysoev.ru         return 0xffffffff;
138*0Sigor@sysoev.ru     }
139*0Sigor@sysoev.ru 
140*0Sigor@sysoev.ru     p++;
141*0Sigor@sysoev.ru 
142*0Sigor@sysoev.ru     if (nxt_fast_path(p + n <= end)) {
143*0Sigor@sysoev.ru 
144*0Sigor@sysoev.ru         do {
145*0Sigor@sysoev.ru             c = *p++;
146*0Sigor@sysoev.ru             /*
147*0Sigor@sysoev.ru              * The byte must in the 0x80 - 0xbf range.
148*0Sigor@sysoev.ru              * Values below 0x80 become >= 0x80.
149*0Sigor@sysoev.ru              */
150*0Sigor@sysoev.ru             c = c - 0x80;
151*0Sigor@sysoev.ru 
152*0Sigor@sysoev.ru             if (nxt_slow_path(c > 0x3f)) {
153*0Sigor@sysoev.ru                 return 0xffffffff;
154*0Sigor@sysoev.ru             }
155*0Sigor@sysoev.ru 
156*0Sigor@sysoev.ru             u = (u << 6) | c;
157*0Sigor@sysoev.ru             n--;
158*0Sigor@sysoev.ru 
159*0Sigor@sysoev.ru         } while (n != 0);
160*0Sigor@sysoev.ru 
161*0Sigor@sysoev.ru         if (overlong < u && u < 0x110000) {
162*0Sigor@sysoev.ru             *start = p;
163*0Sigor@sysoev.ru             return u;
164*0Sigor@sysoev.ru         }
165*0Sigor@sysoev.ru     }
166*0Sigor@sysoev.ru 
167*0Sigor@sysoev.ru     return 0xffffffff;
168*0Sigor@sysoev.ru }
169*0Sigor@sysoev.ru 
170*0Sigor@sysoev.ru 
171*0Sigor@sysoev.ru /*
172*0Sigor@sysoev.ru  * nxt_utf8_casecmp() tests only up to the minimum of given lengths, but
173*0Sigor@sysoev.ru  * requires lengths of both strings because otherwise nxt_utf8_decode2()
174*0Sigor@sysoev.ru  * may fail due to incomplete sequence.
175*0Sigor@sysoev.ru  */
176*0Sigor@sysoev.ru 
177*0Sigor@sysoev.ru nxt_int_t
178*0Sigor@sysoev.ru nxt_utf8_casecmp(const u_char *start1, const u_char *start2, size_t len1,
179*0Sigor@sysoev.ru     size_t len2)
180*0Sigor@sysoev.ru {
181*0Sigor@sysoev.ru     int32_t       n;
182*0Sigor@sysoev.ru     uint32_t      u1, u2;
183*0Sigor@sysoev.ru     const u_char  *end1, *end2;
184*0Sigor@sysoev.ru 
185*0Sigor@sysoev.ru     end1 = start1 + len1;
186*0Sigor@sysoev.ru     end2 = start2 + len2;
187*0Sigor@sysoev.ru 
188*0Sigor@sysoev.ru     while (start1 < end1 && start2 < end2) {
189*0Sigor@sysoev.ru 
190*0Sigor@sysoev.ru         u1 = nxt_utf8_lowcase(&start1, end1);
191*0Sigor@sysoev.ru 
192*0Sigor@sysoev.ru         u2 = nxt_utf8_lowcase(&start2, end2);
193*0Sigor@sysoev.ru 
194*0Sigor@sysoev.ru         if (nxt_slow_path((u1 | u2) == 0xffffffff)) {
195*0Sigor@sysoev.ru             return NXT_UTF8_SORT_INVALID;
196*0Sigor@sysoev.ru         }
197*0Sigor@sysoev.ru 
198*0Sigor@sysoev.ru         n = u1 - u2;
199*0Sigor@sysoev.ru 
200*0Sigor@sysoev.ru         if (n != 0) {
201*0Sigor@sysoev.ru             return (nxt_int_t) n;
202*0Sigor@sysoev.ru         }
203*0Sigor@sysoev.ru     }
204*0Sigor@sysoev.ru 
205*0Sigor@sysoev.ru     return 0;
206*0Sigor@sysoev.ru }
207*0Sigor@sysoev.ru 
208*0Sigor@sysoev.ru 
209*0Sigor@sysoev.ru uint32_t
210*0Sigor@sysoev.ru nxt_utf8_lowcase(const u_char **start, const u_char *end)
211*0Sigor@sysoev.ru {
212*0Sigor@sysoev.ru     uint32_t        u;
213*0Sigor@sysoev.ru     const uint32_t  *block;
214*0Sigor@sysoev.ru 
215*0Sigor@sysoev.ru     u = (uint32_t) **start;
216*0Sigor@sysoev.ru 
217*0Sigor@sysoev.ru     if (nxt_fast_path(u < 0x80)) {
218*0Sigor@sysoev.ru         (*start)++;
219*0Sigor@sysoev.ru 
220*0Sigor@sysoev.ru         return nxt_unicode_block_000[u];
221*0Sigor@sysoev.ru     }
222*0Sigor@sysoev.ru 
223*0Sigor@sysoev.ru     u = nxt_utf8_decode2(start, end);
224*0Sigor@sysoev.ru 
225*0Sigor@sysoev.ru     if (u <= NXT_UNICODE_MAX_LOWCASE) {
226*0Sigor@sysoev.ru         block = nxt_unicode_blocks[u / NXT_UNICODE_BLOCK_SIZE];
227*0Sigor@sysoev.ru 
228*0Sigor@sysoev.ru         if (block != NULL) {
229*0Sigor@sysoev.ru             return block[u % NXT_UNICODE_BLOCK_SIZE];
230*0Sigor@sysoev.ru         }
231*0Sigor@sysoev.ru     }
232*0Sigor@sysoev.ru 
233*0Sigor@sysoev.ru     return u;
234*0Sigor@sysoev.ru }
235*0Sigor@sysoev.ru 
236*0Sigor@sysoev.ru 
237*0Sigor@sysoev.ru ssize_t
238*0Sigor@sysoev.ru nxt_utf8_length(const u_char *p, size_t len)
239*0Sigor@sysoev.ru {
240*0Sigor@sysoev.ru     ssize_t       length;
241*0Sigor@sysoev.ru     const u_char  *end;
242*0Sigor@sysoev.ru 
243*0Sigor@sysoev.ru     length = 0;
244*0Sigor@sysoev.ru 
245*0Sigor@sysoev.ru     end = p + len;
246*0Sigor@sysoev.ru 
247*0Sigor@sysoev.ru     while (p < end) {
248*0Sigor@sysoev.ru         if (nxt_slow_path(nxt_utf8_decode(&p, end) == 0xffffffff)) {
249*0Sigor@sysoev.ru             return -1;
250*0Sigor@sysoev.ru         }
251*0Sigor@sysoev.ru 
252*0Sigor@sysoev.ru         length++;
253*0Sigor@sysoev.ru     }
254*0Sigor@sysoev.ru 
255*0Sigor@sysoev.ru     return length;
256*0Sigor@sysoev.ru }
257*0Sigor@sysoev.ru 
258*0Sigor@sysoev.ru 
259*0Sigor@sysoev.ru nxt_bool_t
260*0Sigor@sysoev.ru nxt_utf8_is_valid(const u_char *p, size_t len)
261*0Sigor@sysoev.ru {
262*0Sigor@sysoev.ru     const u_char  *end;
263*0Sigor@sysoev.ru 
264*0Sigor@sysoev.ru     end = p + len;
265*0Sigor@sysoev.ru 
266*0Sigor@sysoev.ru     while (p < end) {
267*0Sigor@sysoev.ru         if (nxt_slow_path(nxt_utf8_decode(&p, end) == 0xffffffff)) {
268*0Sigor@sysoev.ru             return 0;
269*0Sigor@sysoev.ru         }
270*0Sigor@sysoev.ru     }
271*0Sigor@sysoev.ru 
272*0Sigor@sysoev.ru     return 1;
273*0Sigor@sysoev.ru }
274