Coverage Report

Created: 2026-09-28 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quickjs/libunicode.c
Line
Count
Source
1
/*
2
 * Unicode utilities
3
 *
4
 * Copyright (c) 2017-2018 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <stdarg.h>
27
#include <string.h>
28
#include <assert.h>
29
30
#include "cutils.h"
31
#include "libunicode.h"
32
#include "libunicode-table.h"
33
34
enum {
35
    RUN_TYPE_U,
36
    RUN_TYPE_L,
37
    RUN_TYPE_UF,
38
    RUN_TYPE_LF,
39
    RUN_TYPE_UL,
40
    RUN_TYPE_LSU,
41
    RUN_TYPE_U2L_399_EXT2,
42
    RUN_TYPE_UF_D20,
43
    RUN_TYPE_UF_D1_EXT,
44
    RUN_TYPE_U_EXT,
45
    RUN_TYPE_LF_EXT,
46
    RUN_TYPE_UF_EXT2,
47
    RUN_TYPE_LF_EXT2,
48
    RUN_TYPE_UF_EXT3,
49
};
50
51
static int lre_case_conv1(uint32_t c, int conv_type)
52
0
{
53
0
    uint32_t res[LRE_CC_RES_LEN_MAX];
54
0
    lre_case_conv(res, c, conv_type);
55
0
    return res[0];
56
0
}
57
58
/* case conversion using the table entry 'idx' with value 'v' */
59
static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v)
60
16.8M
{
61
16.8M
    uint32_t code, data, type, a, is_lower;
62
16.8M
    is_lower = (conv_type != 0);
63
16.8M
    type = (v >> (32 - 17 - 7 - 4)) & 0xf;
64
16.8M
    data = ((v & 0xf) << 8) | case_conv_table2[idx];
65
16.8M
    code = v >> (32 - 17);
66
16.8M
    switch(type) {
67
6.62M
    case RUN_TYPE_U:
68
6.62M
    case RUN_TYPE_L:
69
7.82M
    case RUN_TYPE_UF:
70
7.82M
    case RUN_TYPE_LF:
71
7.82M
        if (conv_type == (type & 1) ||
72
7.82M
            (type >= RUN_TYPE_UF && conv_type == 2)) {
73
7.82M
            c = c - code + (case_conv_table1[data] >> (32 - 17));
74
7.82M
        }
75
7.82M
        break;
76
7.23M
    case RUN_TYPE_UL:
77
7.23M
        a = c - code;
78
7.23M
        if ((a & 1) != (1 - is_lower))
79
242
            break;
80
7.23M
        c = (a ^ 1) + code;
81
7.23M
        break;
82
84.9k
    case RUN_TYPE_LSU:
83
84.9k
        a = c - code;
84
84.9k
        if (a == 1) {
85
42.4k
            c += 2 * is_lower - 1;
86
42.4k
        } else if (a == (1 - is_lower) * 2) {
87
42.4k
            c += (2 * is_lower - 1) * 2;
88
42.4k
        }
89
84.9k
        break;
90
377k
    case RUN_TYPE_U2L_399_EXT2:
91
377k
        if (!is_lower) {
92
377k
            res[0] = c - code + case_conv_ext[data >> 6];
93
377k
            res[1] = 0x399;
94
377k
            return 2;
95
377k
        } else {
96
0
            c = c - code + case_conv_ext[data & 0x3f];
97
0
        }
98
0
        break;
99
259k
    case RUN_TYPE_UF_D20:
100
259k
        if (conv_type == 1)
101
0
            break;
102
259k
        c = data + (conv_type == 2) * 0x20;
103
259k
        break;
104
41.9k
    case RUN_TYPE_UF_D1_EXT:
105
41.9k
        if (conv_type == 1)
106
0
            break;
107
41.9k
        c = case_conv_ext[data] + (conv_type == 2);
108
41.9k
        break;
109
10.6k
    case RUN_TYPE_U_EXT:
110
10.6k
    case RUN_TYPE_LF_EXT:
111
10.6k
        if (is_lower != (type - RUN_TYPE_U_EXT))
112
0
            break;
113
10.6k
        c = case_conv_ext[data];
114
10.6k
        break;
115
0
    case RUN_TYPE_LF_EXT2:
116
0
        if (!is_lower)
117
0
            break;
118
0
        res[0] = c - code + case_conv_ext[data >> 6];
119
0
        res[1] = case_conv_ext[data & 0x3f];
120
0
        return 2;
121
812k
    case RUN_TYPE_UF_EXT2:
122
812k
        if (conv_type == 1)
123
0
            break;
124
812k
        res[0] = c - code + case_conv_ext[data >> 6];
125
812k
        res[1] = case_conv_ext[data & 0x3f];
126
812k
        if (conv_type == 2) {
127
            /* convert to lower */
128
0
            res[0] = lre_case_conv1(res[0], 1);
129
0
            res[1] = lre_case_conv1(res[1], 1);
130
0
        }
131
812k
        return 2;
132
0
    default:
133
223k
    case RUN_TYPE_UF_EXT3:
134
223k
        if (conv_type == 1)
135
0
            break;
136
223k
        res[0] = case_conv_ext[data >> 8];
137
223k
        res[1] = case_conv_ext[(data >> 4) & 0xf];
138
223k
        res[2] = case_conv_ext[data & 0xf];
139
223k
        if (conv_type == 2) {
140
            /* convert to lower */
141
0
            res[0] = lre_case_conv1(res[0], 1);
142
0
            res[1] = lre_case_conv1(res[1], 1);
143
0
            res[2] = lre_case_conv1(res[2], 1);
144
0
        }
145
223k
        return 3;
146
16.8M
    }
147
15.4M
    res[0] = c;
148
15.4M
    return 1;
149
16.8M
}
150
151
/* conv_type:
152
   0 = to upper
153
   1 = to lower
154
   2 = case folding (= to lower with modifications)
155
*/
156
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
157
0
{
158
0
    if (c < 128) {
159
0
        if (conv_type) {
160
0
            if (c >= 'A' && c <= 'Z') {
161
0
                c = c - 'A' + 'a';
162
0
            }
163
0
        } else {
164
0
            if (c >= 'a' && c <= 'z') {
165
0
                c = c - 'a' + 'A';
166
0
            }
167
0
        }
168
0
    } else {
169
0
        uint32_t v, code, len;
170
0
        int idx, idx_min, idx_max;
171
172
0
        idx_min = 0;
173
0
        idx_max = countof(case_conv_table1) - 1;
174
0
        while (idx_min <= idx_max) {
175
0
            idx = (unsigned)(idx_max + idx_min) / 2;
176
0
            v = case_conv_table1[idx];
177
0
            code = v >> (32 - 17);
178
0
            len = (v >> (32 - 17 - 7)) & 0x7f;
179
0
            if (c < code) {
180
0
                idx_max = idx - 1;
181
0
            } else if (c >= code + len) {
182
0
                idx_min = idx + 1;
183
0
            } else {
184
0
                return lre_case_conv_entry(res, c, conv_type, idx, v);
185
0
            }
186
0
        }
187
0
    }
188
0
    res[0] = c;
189
0
    return 1;
190
0
}
191
192
static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode)
193
17.1M
{
194
17.1M
    uint32_t res[LRE_CC_RES_LEN_MAX];
195
17.1M
    int len;
196
197
17.1M
    if (is_unicode) {
198
0
        len = lre_case_conv_entry(res, c, 2, idx, v);
199
0
        if (len == 1) {
200
0
            c = res[0];
201
0
        } else {
202
            /* handle the few specific multi-character cases (see
203
               unicode_gen.c:dump_case_folding_special_cases()) */
204
0
            if (c == 0xfb06) {
205
0
                c = 0xfb05;
206
0
            } else if (c == 0x01fd3) {
207
0
                c = 0x390;
208
0
            } else if (c == 0x01fe3) {
209
0
                c = 0x3b0;
210
0
            }
211
0
        }
212
17.1M
    } else {
213
17.1M
        if (likely(c < 128)) {
214
276k
            if (c >= 'a' && c <= 'z')
215
276k
                c = c - 'a' + 'A';
216
16.8M
        } else {
217
            /* legacy regexp: to upper case if single char >= 128 */
218
16.8M
            len = lre_case_conv_entry(res, c, FALSE, idx, v);
219
16.8M
            if (len == 1 && res[0] >= 128)
220
15.4M
                c = res[0];
221
16.8M
        }
222
17.1M
    }
223
17.1M
    return c;
224
17.1M
}
225
226
/* JS regexp specific rules for case folding */
227
int lre_canonicalize(uint32_t c, BOOL is_unicode)
228
354k
{
229
354k
    if (c < 128) {
230
        /* fast case */
231
352k
        if (is_unicode) {
232
0
            if (c >= 'A' && c <= 'Z') {
233
0
                c = c - 'A' + 'a';
234
0
            }
235
352k
        } else {
236
352k
            if (c >= 'a' && c <= 'z') {
237
15.9k
                c = c - 'a' + 'A';
238
15.9k
            }
239
352k
        }
240
352k
    } else {
241
1.92k
        uint32_t v, code, len;
242
1.92k
        int idx, idx_min, idx_max;
243
244
1.92k
        idx_min = 0;
245
1.92k
        idx_max = countof(case_conv_table1) - 1;
246
19.0k
        while (idx_min <= idx_max) {
247
17.3k
            idx = (unsigned)(idx_max + idx_min) / 2;
248
17.3k
            v = case_conv_table1[idx];
249
17.3k
            code = v >> (32 - 17);
250
17.3k
            len = (v >> (32 - 17 - 7)) & 0x7f;
251
17.3k
            if (c < code) {
252
2.41k
                idx_max = idx - 1;
253
14.9k
            } else if (c >= code + len) {
254
14.6k
                idx_min = idx + 1;
255
14.6k
            } else {
256
242
                return lre_case_folding_entry(c, idx, v, is_unicode);
257
242
            }
258
17.3k
        }
259
1.92k
    }
260
354k
    return c;
261
354k
}
262
263
static uint32_t get_le24(const uint8_t *ptr)
264
49
{
265
49
    return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
266
49
}
267
268
3
#define UNICODE_INDEX_BLOCK_LEN 32
269
270
/* return -1 if not in table, otherwise the offset in the block */
271
static int get_index_pos(uint32_t *pcode, uint32_t c,
272
                         const uint8_t *index_table, int index_table_len)
273
15
{
274
15
    uint32_t code, v;
275
15
    int idx_min, idx_max, idx;
276
277
15
    idx_min = 0;
278
15
    v = get_le24(index_table);
279
15
    code = v & ((1 << 21) - 1);
280
15
    if (c < code) {
281
1
        *pcode = 0;
282
1
        return 0;
283
1
    }
284
14
    idx_max = index_table_len - 1;
285
14
    code = get_le24(index_table + idx_max * 3);
286
14
    if (c >= code)
287
11
        return -1;
288
    /* invariant: tab[idx_min] <= c < tab2[idx_max] */
289
20
    while ((idx_max - idx_min) > 1) {
290
17
        idx = (idx_max + idx_min) / 2;
291
17
        v = get_le24(index_table + idx * 3);
292
17
        code = v & ((1 << 21) - 1);
293
17
        if (c < code) {
294
2
            idx_max = idx;
295
15
        } else {
296
15
            idx_min = idx;
297
15
        }
298
17
    }
299
3
    v = get_le24(index_table + idx_min * 3);
300
3
    *pcode = v & ((1 << 21) - 1);
301
3
    return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21);
302
14
}
303
304
static BOOL lre_is_in_table(uint32_t c, const uint8_t *table,
305
                            const uint8_t *index_table, int index_table_len)
306
15
{
307
15
    uint32_t code, b, bit;
308
15
    int pos;
309
15
    const uint8_t *p;
310
311
15
    pos = get_index_pos(&code, c, index_table, index_table_len);
312
15
    if (pos < 0)
313
11
        return FALSE; /* outside the table */
314
4
    p = table + pos;
315
4
    bit = 0;
316
    /* Compressed run length encoding:
317
       00..3F: 2 packed lengths: 3-bit + 3-bit
318
       40..5F: 5-bits plus extra byte for length
319
       60..7F: 5-bits plus 2 extra bytes for length
320
       80..FF: 7-bit length
321
       lengths must be incremented to get character count
322
       Ranges alternate between false and true return value.
323
     */
324
60
    for(;;) {
325
60
        b = *p++;
326
60
        if (b < 64) {
327
11
            code += (b >> 3) + 1;
328
11
            if (c < code)
329
0
                return bit;
330
11
            bit ^= 1;
331
11
            code += (b & 7) + 1;
332
49
        } else if (b >= 0x80) {
333
38
            code += b - 0x80 + 1;
334
38
        } else if (b < 0x60) {
335
8
            code += (((b - 0x40) << 8) | p[0]) + 1;
336
8
            p++;
337
8
        } else {
338
3
            code += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1;
339
3
            p += 2;
340
3
        }
341
60
        if (c < code)
342
4
            return bit;
343
56
        bit ^= 1;
344
56
    }
345
4
}
346
347
BOOL lre_is_cased(uint32_t c)
348
0
{
349
0
    uint32_t v, code, len;
350
0
    int idx, idx_min, idx_max;
351
352
0
    idx_min = 0;
353
0
    idx_max = countof(case_conv_table1) - 1;
354
0
    while (idx_min <= idx_max) {
355
0
        idx = (unsigned)(idx_max + idx_min) / 2;
356
0
        v = case_conv_table1[idx];
357
0
        code = v >> (32 - 17);
358
0
        len = (v >> (32 - 17 - 7)) & 0x7f;
359
0
        if (c < code) {
360
0
            idx_max = idx - 1;
361
0
        } else if (c >= code + len) {
362
0
            idx_min = idx + 1;
363
0
        } else {
364
0
            return TRUE;
365
0
        }
366
0
    }
367
0
    return lre_is_in_table(c, unicode_prop_Cased1_table,
368
0
                           unicode_prop_Cased1_index,
369
0
                           sizeof(unicode_prop_Cased1_index) / 3);
370
0
}
371
372
BOOL lre_is_case_ignorable(uint32_t c)
373
0
{
374
0
    return lre_is_in_table(c, unicode_prop_Case_Ignorable_table,
375
0
                           unicode_prop_Case_Ignorable_index,
376
0
                           sizeof(unicode_prop_Case_Ignorable_index) / 3);
377
0
}
378
379
/* character range */
380
381
static __maybe_unused void cr_dump(CharRange *cr)
382
0
{
383
0
    int i;
384
0
    for(i = 0; i < cr->len; i++)
385
0
        printf("%d: 0x%04x\n", i, cr->points[i]);
386
0
}
387
388
static void *cr_default_realloc(void *opaque, void *ptr, size_t size)
389
0
{
390
0
    return realloc(ptr, size);
391
0
}
392
393
void cr_init(CharRange *cr, void *mem_opaque, DynBufReallocFunc *realloc_func)
394
101k
{
395
101k
    cr->len = cr->size = 0;
396
101k
    cr->points = NULL;
397
101k
    cr->mem_opaque = mem_opaque;
398
101k
    cr->realloc_func = realloc_func ? realloc_func : cr_default_realloc;
399
101k
}
400
401
void cr_free(CharRange *cr)
402
293k
{
403
293k
    cr->realloc_func(cr->mem_opaque, cr->points, 0);
404
293k
}
405
406
int cr_realloc(CharRange *cr, int size)
407
2.86M
{
408
2.86M
    int new_size;
409
2.86M
    uint32_t *new_buf;
410
411
2.86M
    if (size > cr->size) {
412
2.84M
        new_size = max_int(size, cr->size * 3 / 2);
413
2.84M
        new_buf = cr->realloc_func(cr->mem_opaque, cr->points,
414
2.84M
                                   new_size * sizeof(cr->points[0]));
415
2.84M
        if (!new_buf)
416
0
            return -1;
417
2.84M
        cr->points = new_buf;
418
2.84M
        cr->size = new_size;
419
2.84M
    }
420
2.86M
    return 0;
421
2.86M
}
422
423
int cr_copy(CharRange *cr, const CharRange *cr1)
424
0
{
425
0
    if (cr_realloc(cr, cr1->len))
426
0
        return -1;
427
0
    memcpy(cr->points, cr1->points, sizeof(cr->points[0]) * cr1->len);
428
0
    cr->len = cr1->len;
429
0
    return 0;
430
0
}
431
432
/* merge consecutive intervals and remove empty intervals */
433
static void cr_compress(CharRange *cr)
434
258k
{
435
258k
    int i, j, k, len;
436
258k
    uint32_t *pt;
437
438
258k
    pt = cr->points;
439
258k
    len = cr->len;
440
258k
    i = 0;
441
258k
    j = 0;
442
258k
    k = 0;
443
57.2M
    while ((i + 1) < len) {
444
57.0M
        if (pt[i] == pt[i + 1]) {
445
            /* empty interval */
446
1.91M
            i += 2;
447
55.1M
        } else {
448
55.1M
            j = i;
449
56.6M
            while ((j + 3) < len && pt[j + 1] == pt[j + 2])
450
1.56M
                j += 2;
451
            /* just copy */
452
55.1M
            pt[k] = pt[i];
453
55.1M
            pt[k + 1] = pt[j + 1];
454
55.1M
            k += 2;
455
55.1M
            i = j + 2;
456
55.1M
        }
457
57.0M
    }
458
258k
    cr->len = k;
459
258k
}
460
461
/* union or intersection */
462
int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
463
          const uint32_t *b_pt, int b_len, int op)
464
242k
{
465
242k
    int a_idx, b_idx, is_in;
466
242k
    uint32_t v;
467
468
242k
    a_idx = 0;
469
242k
    b_idx = 0;
470
103M
    for(;;) {
471
        /* get one more point from a or b in increasing order */
472
103M
        if (a_idx < a_len && b_idx < b_len) {
473
58.5M
            if (a_pt[a_idx] < b_pt[b_idx]) {
474
41.4M
                goto a_add;
475
41.4M
            } else if (a_pt[a_idx] == b_pt[b_idx]) {
476
15.3M
                v = a_pt[a_idx];
477
15.3M
                a_idx++;
478
15.3M
                b_idx++;
479
15.3M
            } else {
480
1.85M
                goto b_add;
481
1.85M
            }
482
58.5M
        } else if (a_idx < a_len) {
483
70.2M
        a_add:
484
70.2M
            v = a_pt[a_idx++];
485
70.2M
        } else if (b_idx < b_len) {
486
18.2M
        b_add:
487
18.2M
            v = b_pt[b_idx++];
488
18.2M
        } else {
489
242k
            break;
490
242k
        }
491
        /* add the point if the in/out status changes */
492
103M
        switch(op) {
493
57.6M
        case CR_OP_UNION:
494
57.6M
            is_in = (a_idx & 1) | (b_idx & 1);
495
57.6M
            break;
496
46.1M
        case CR_OP_INTER:
497
46.1M
            is_in = (a_idx & 1) & (b_idx & 1);
498
46.1M
            break;
499
0
        case CR_OP_XOR:
500
0
            is_in = (a_idx & 1) ^ (b_idx & 1);
501
0
            break;
502
0
        case CR_OP_SUB:
503
0
            is_in = (a_idx & 1) & ((b_idx & 1) ^ 1);
504
0
            break;
505
0
        default:
506
0
            abort();
507
103M
        }
508
103M
        if (is_in != (cr->len & 1)) {
509
92.2M
            if (cr_add_point(cr, v))
510
0
                return -1;
511
92.2M
        }
512
103M
    }
513
242k
    cr_compress(cr);
514
242k
    return 0;
515
242k
}
516
517
int cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op)
518
192k
{
519
192k
    CharRange a = *cr;
520
192k
    int ret;
521
192k
    cr->len = 0;
522
192k
    cr->size = 0;
523
192k
    cr->points = NULL;
524
192k
    ret = cr_op(cr, a.points, a.len, b_pt, b_len, op);
525
192k
    cr_free(&a);
526
192k
    return ret;
527
192k
}
528
529
int cr_invert(CharRange *cr)
530
16.6k
{
531
16.6k
    int len;
532
16.6k
    len = cr->len;
533
16.6k
    if (cr_realloc(cr, len + 2))
534
0
        return -1;
535
16.6k
    memmove(cr->points + 1, cr->points, len * sizeof(cr->points[0]));
536
16.6k
    cr->points[0] = 0;
537
16.6k
    cr->points[len + 1] = UINT32_MAX;
538
16.6k
    cr->len = len + 2;
539
16.6k
    cr_compress(cr);
540
16.6k
    return 0;
541
16.6k
}
542
543
2.18M
#define CASE_U (1 << 0)
544
1.04M
#define CASE_L (1 << 1)
545
1.04M
#define CASE_F (1 << 2)
546
547
/* use the case conversion table to generate range of characters.
548
   CASE_U: set char if modified by uppercasing,
549
   CASE_L: set char if modified by lowercasing,
550
   CASE_F: set char if modified by case folding,
551
 */
552
static int unicode_case1(CharRange *cr, int case_mask)
553
16.6k
{
554
482k
#define MR(x) (1 << RUN_TYPE_ ## x)
555
16.6k
    const uint32_t tab_run_mask[3] = {
556
16.6k
        MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
557
16.6k
        MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
558
559
16.6k
        MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),
560
561
16.6k
        MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
562
16.6k
    };
563
16.6k
#undef MR
564
16.6k
    uint32_t mask, v, code, type, len, i, idx;
565
566
16.6k
    if (case_mask == 0)
567
0
        return 0;
568
16.6k
    mask = 0;
569
66.5k
    for(i = 0; i < 3; i++) {
570
49.9k
        if ((case_mask >> i) & 1)
571
16.6k
            mask |= tab_run_mask[i];
572
49.9k
    }
573
6.30M
    for(idx = 0; idx < countof(case_conv_table1); idx++) {
574
6.29M
        v = case_conv_table1[idx];
575
6.29M
        type = (v >> (32 - 17 - 7 - 4)) & 0xf;
576
6.29M
        code = v >> (32 - 17);
577
6.29M
        len = (v >> (32 - 17 - 7)) & 0x7f;
578
6.29M
        if ((mask >> type) & 1) {
579
            //            printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1);
580
4.31M
            switch(type) {
581
981k
            case RUN_TYPE_UL:
582
981k
                if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
583
0
                    goto def_case;
584
981k
                code += ((case_mask & CASE_U) != 0);
585
10.0M
                for(i = 0; i < len; i += 2) {
586
9.06M
                    if (cr_add_interval(cr, code + i, code + i + 1))
587
0
                        return -1;
588
9.06M
                }
589
981k
                break;
590
981k
            case RUN_TYPE_LSU:
591
66.5k
                if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
592
0
                    goto def_case;
593
66.5k
                if (!(case_mask & CASE_U)) {
594
0
                    if (cr_add_interval(cr, code, code + 1))
595
0
                        return -1;
596
0
                }
597
66.5k
                if (cr_add_interval(cr, code + 1, code + 2))
598
0
                    return -1;
599
66.5k
                if (case_mask & CASE_U) {
600
66.5k
                    if (cr_add_interval(cr, code + 2, code + 3))
601
0
                        return -1;
602
66.5k
                }
603
66.5k
                break;
604
3.26M
            default:
605
3.26M
            def_case:
606
3.26M
                if (cr_add_interval(cr, code, code + len))
607
0
                    return -1;
608
3.26M
                break;
609
4.31M
            }
610
4.31M
        }
611
6.29M
    }
612
16.6k
    return 0;
613
16.6k
}
614
615
static int point_cmp(const void *p1, const void *p2, void *arg)
616
79.2M
{
617
79.2M
    uint32_t v1 = *(uint32_t *)p1;
618
79.2M
    uint32_t v2 = *(uint32_t *)p2;
619
79.2M
    return (v1 > v2) - (v1 < v2);
620
79.2M
}
621
622
static void cr_sort_and_remove_overlap(CharRange *cr)
623
16.6k
{
624
16.6k
    uint32_t start, end, start1, end1, i, j;
625
626
    /* the resulting ranges are not necessarily sorted and may overlap */
627
16.6k
    rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);
628
16.6k
    j = 0;
629
8.22M
    for(i = 0; i < cr->len; ) {
630
8.20M
        start = cr->points[i];
631
8.20M
        end = cr->points[i + 1];
632
8.20M
        i += 2;
633
9.31M
        while (i < cr->len) {
634
9.30M
            start1 = cr->points[i];
635
9.30M
            end1 = cr->points[i + 1];
636
9.30M
            if (start1 > end) {
637
                /* |------|
638
                 *           |-------| */
639
8.18M
                break;
640
8.18M
            } else if (end1 <= end) {
641
                /* |------|
642
                 *    |--| */
643
313k
                i += 2;
644
799k
            } else {
645
                /* |------|
646
                 *     |-------| */
647
799k
                end = end1;
648
799k
                i += 2;
649
799k
            }
650
9.30M
        }
651
8.20M
        cr->points[j] = start;
652
8.20M
        cr->points[j + 1] = end;
653
8.20M
        j += 2;
654
8.20M
    }
655
16.6k
    cr->len = j;
656
16.6k
}
657
658
/* canonicalize a character set using the JS regex case folding rules
659
   (see lre_canonicalize()) */
660
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
661
16.6k
{
662
16.6k
    CharRange cr_inter, cr_mask, cr_result, cr_sub;
663
16.6k
    uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
664
665
16.6k
    cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
666
16.6k
    cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
667
16.6k
    cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
668
16.6k
    cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
669
670
16.6k
    if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
671
0
        goto fail;
672
16.6k
    if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
673
0
        goto fail;
674
675
16.6k
    if (cr_invert(&cr_mask))
676
0
        goto fail;
677
16.6k
    if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
678
0
        goto fail;
679
680
    /* cr_inter = cr & cr_mask */
681
    /* cr_sub = cr & ~cr_mask */
682
683
    /* use the case conversion table to compute the result */
684
16.6k
    d_start = -1;
685
16.6k
    d_end = -1;
686
16.6k
    idx = 0;
687
16.6k
    v = case_conv_table1[idx];
688
16.6k
    code = v >> (32 - 17);
689
16.6k
    len = (v >> (32 - 17 - 7)) & 0x7f;
690
8.29M
    for(i = 0; i < cr_inter.len; i += 2) {
691
8.27M
        start = cr_inter.points[i];
692
8.27M
        end = cr_inter.points[i + 1];
693
694
25.4M
        for(c = start; c < end; c++) {
695
22.1M
            for(;;) {
696
22.1M
                if (c >= code && c < code + len)
697
17.1M
                    break;
698
5.01M
                idx++;
699
5.01M
                assert(idx < countof(case_conv_table1));
700
5.01M
                v = case_conv_table1[idx];
701
5.01M
                code = v >> (32 - 17);
702
5.01M
                len = (v >> (32 - 17 - 7)) & 0x7f;
703
5.01M
            }
704
17.1M
            d = lre_case_folding_entry(c, idx, v, is_unicode);
705
            /* try to merge with the current interval */
706
17.1M
            if (d_start == -1) {
707
15.1k
                d_start = d;
708
15.1k
                d_end = d + 1;
709
17.1M
            } else if (d_end == d) {
710
7.83M
                d_end++;
711
9.30M
            } else {
712
9.30M
                cr_add_interval(&cr_result, d_start, d_end);
713
9.30M
                d_start = d;
714
9.30M
                d_end = d + 1;
715
9.30M
            }
716
17.1M
        }
717
8.27M
    }
718
16.6k
    if (d_start != -1) {
719
15.1k
        if (cr_add_interval(&cr_result, d_start, d_end))
720
0
            goto fail;
721
15.1k
    }
722
723
    /* the resulting ranges are not necessarily sorted and may overlap */
724
16.6k
    cr_sort_and_remove_overlap(&cr_result);
725
726
    /* or with the character not affected by the case folding */
727
16.6k
    cr->len = 0;
728
16.6k
    if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))
729
0
        goto fail;
730
731
16.6k
    cr_free(&cr_inter);
732
16.6k
    cr_free(&cr_mask);
733
16.6k
    cr_free(&cr_result);
734
16.6k
    cr_free(&cr_sub);
735
16.6k
    return 0;
736
0
 fail:
737
0
    cr_free(&cr_inter);
738
0
    cr_free(&cr_mask);
739
0
    cr_free(&cr_result);
740
0
    cr_free(&cr_sub);
741
0
    return -1;
742
16.6k
}
743
744
#ifdef CONFIG_ALL_UNICODE
745
746
BOOL lre_is_id_start(uint32_t c)
747
13
{
748
13
    return lre_is_in_table(c, unicode_prop_ID_Start_table,
749
13
                           unicode_prop_ID_Start_index,
750
13
                           sizeof(unicode_prop_ID_Start_index) / 3);
751
13
}
752
753
BOOL lre_is_id_continue(uint32_t c)
754
4
{
755
4
    return lre_is_id_start(c) ||
756
2
        lre_is_in_table(c, unicode_prop_ID_Continue1_table,
757
2
                        unicode_prop_ID_Continue1_index,
758
2
                        sizeof(unicode_prop_ID_Continue1_index) / 3);
759
4
}
760
761
#define UNICODE_DECOMP_LEN_MAX 18
762
763
typedef enum {
764
    DECOMP_TYPE_C1, /* 16 bit char */
765
    DECOMP_TYPE_L1, /* 16 bit char table */
766
    DECOMP_TYPE_L2,
767
    DECOMP_TYPE_L3,
768
    DECOMP_TYPE_L4,
769
    DECOMP_TYPE_L5, /* XXX: not used */
770
    DECOMP_TYPE_L6, /* XXX: could remove */
771
    DECOMP_TYPE_L7, /* XXX: could remove */
772
    DECOMP_TYPE_LL1, /* 18 bit char table */
773
    DECOMP_TYPE_LL2,
774
    DECOMP_TYPE_S1, /* 8 bit char table */
775
    DECOMP_TYPE_S2,
776
    DECOMP_TYPE_S3,
777
    DECOMP_TYPE_S4,
778
    DECOMP_TYPE_S5,
779
    DECOMP_TYPE_I1, /* increment 16 bit char value */
780
    DECOMP_TYPE_I2_0,
781
    DECOMP_TYPE_I2_1,
782
    DECOMP_TYPE_I3_1,
783
    DECOMP_TYPE_I3_2,
784
    DECOMP_TYPE_I4_1,
785
    DECOMP_TYPE_I4_2,
786
    DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */
787
    DECOMP_TYPE_B2,
788
    DECOMP_TYPE_B3,
789
    DECOMP_TYPE_B4,
790
    DECOMP_TYPE_B5,
791
    DECOMP_TYPE_B6,
792
    DECOMP_TYPE_B7,
793
    DECOMP_TYPE_B8,
794
    DECOMP_TYPE_B18,
795
    DECOMP_TYPE_LS2,
796
    DECOMP_TYPE_PAT3,
797
    DECOMP_TYPE_S2_UL,
798
    DECOMP_TYPE_LS2_UL,
799
} DecompTypeEnum;
800
801
static uint32_t unicode_get_short_code(uint32_t c)
802
0
{
803
0
    static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 };
804
805
0
    if (c < 0x80)
806
0
        return c;
807
0
    else if (c < 0x80 + 0x50)
808
0
        return c - 0x80 + 0x300;
809
0
    else
810
0
        return unicode_short_table[c - 0x80 - 0x50];
811
0
}
812
813
static uint32_t unicode_get_lower_simple(uint32_t c)
814
0
{
815
0
    if (c < 0x100 || (c >= 0x410 && c <= 0x42f))
816
0
        c += 0x20;
817
0
    else
818
0
        c++;
819
0
    return c;
820
0
}
821
822
static uint16_t unicode_get16(const uint8_t *p)
823
0
{
824
0
    return p[0] | (p[1] << 8);
825
0
}
826
827
static int unicode_decomp_entry(uint32_t *res, uint32_t c,
828
                                int idx, uint32_t code, uint32_t len,
829
                                uint32_t type)
830
0
{
831
0
    uint32_t c1;
832
0
    int l, i, p;
833
0
    const uint8_t *d;
834
835
0
    if (type == DECOMP_TYPE_C1) {
836
0
        res[0] = unicode_decomp_table2[idx];
837
0
        return 1;
838
0
    } else {
839
0
        d = unicode_decomp_data + unicode_decomp_table2[idx];
840
0
        switch(type) {
841
0
        case DECOMP_TYPE_L1:
842
0
        case DECOMP_TYPE_L2:
843
0
        case DECOMP_TYPE_L3:
844
0
        case DECOMP_TYPE_L4:
845
0
        case DECOMP_TYPE_L5:
846
0
        case DECOMP_TYPE_L6:
847
0
        case DECOMP_TYPE_L7:
848
0
            l = type - DECOMP_TYPE_L1 + 1;
849
0
            d += (c - code) * l * 2;
850
0
            for(i = 0; i < l; i++) {
851
0
                if ((res[i] = unicode_get16(d + 2 * i)) == 0)
852
0
                    return 0;
853
0
            }
854
0
            return l;
855
0
        case DECOMP_TYPE_LL1:
856
0
        case DECOMP_TYPE_LL2:
857
0
            {
858
0
                uint32_t k, p;
859
0
                l = type - DECOMP_TYPE_LL1 + 1;
860
0
                k = (c - code) * l;
861
0
                p = len * l * 2;
862
0
                for(i = 0; i < l; i++) {
863
0
                    c1 = unicode_get16(d + 2 * k) |
864
0
                        (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16);
865
0
                    if (!c1)
866
0
                        return 0;
867
0
                    res[i] = c1;
868
0
                    k++;
869
0
                }
870
0
            }
871
0
            return l;
872
0
        case DECOMP_TYPE_S1:
873
0
        case DECOMP_TYPE_S2:
874
0
        case DECOMP_TYPE_S3:
875
0
        case DECOMP_TYPE_S4:
876
0
        case DECOMP_TYPE_S5:
877
0
            l = type - DECOMP_TYPE_S1 + 1;
878
0
            d += (c - code) * l;
879
0
            for(i = 0; i < l; i++) {
880
0
                if ((res[i] = unicode_get_short_code(d[i])) == 0)
881
0
                    return 0;
882
0
            }
883
0
            return l;
884
0
        case DECOMP_TYPE_I1:
885
0
            l = 1;
886
0
            p = 0;
887
0
            goto decomp_type_i;
888
0
        case DECOMP_TYPE_I2_0:
889
0
        case DECOMP_TYPE_I2_1:
890
0
        case DECOMP_TYPE_I3_1:
891
0
        case DECOMP_TYPE_I3_2:
892
0
        case DECOMP_TYPE_I4_1:
893
0
        case DECOMP_TYPE_I4_2:
894
0
            l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1);
895
0
            p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2);
896
0
        decomp_type_i:
897
0
            for(i = 0; i < l; i++) {
898
0
                c1 = unicode_get16(d + 2 * i);
899
0
                if (i == p)
900
0
                    c1 += c - code;
901
0
                res[i] = c1;
902
0
            }
903
0
            return l;
904
0
        case DECOMP_TYPE_B18:
905
0
            l = 18;
906
0
            goto decomp_type_b;
907
0
        case DECOMP_TYPE_B1:
908
0
        case DECOMP_TYPE_B2:
909
0
        case DECOMP_TYPE_B3:
910
0
        case DECOMP_TYPE_B4:
911
0
        case DECOMP_TYPE_B5:
912
0
        case DECOMP_TYPE_B6:
913
0
        case DECOMP_TYPE_B7:
914
0
        case DECOMP_TYPE_B8:
915
0
            l = type - DECOMP_TYPE_B1 + 1;
916
0
        decomp_type_b:
917
0
            {
918
0
                uint32_t c_min;
919
0
                c_min = unicode_get16(d);
920
0
                d += 2 + (c - code) * l;
921
0
                for(i = 0; i < l; i++) {
922
0
                    c1 = d[i];
923
0
                    if (c1 == 0xff)
924
0
                        c1 = 0x20;
925
0
                    else
926
0
                        c1 += c_min;
927
0
                    res[i] = c1;
928
0
                }
929
0
            }
930
0
            return l;
931
0
        case DECOMP_TYPE_LS2:
932
0
            d += (c - code) * 3;
933
0
            if (!(res[0] = unicode_get16(d)))
934
0
                return 0;
935
0
            res[1] = unicode_get_short_code(d[2]);
936
0
            return 2;
937
0
        case DECOMP_TYPE_PAT3:
938
0
            res[0] = unicode_get16(d);
939
0
            res[2] = unicode_get16(d + 2);
940
0
            d += 4 + (c - code) * 2;
941
0
            res[1] = unicode_get16(d);
942
0
            return 3;
943
0
        case DECOMP_TYPE_S2_UL:
944
0
        case DECOMP_TYPE_LS2_UL:
945
0
            c1 = c - code;
946
0
            if (type == DECOMP_TYPE_S2_UL) {
947
0
                d += c1 & ~1;
948
0
                c = unicode_get_short_code(*d);
949
0
                d++;
950
0
            } else {
951
0
                d += (c1 >> 1) * 3;
952
0
                c = unicode_get16(d);
953
0
                d += 2;
954
0
            }
955
0
            if (c1 & 1)
956
0
                c = unicode_get_lower_simple(c);
957
0
            res[0] = c;
958
0
            res[1] = unicode_get_short_code(*d);
959
0
            return 2;
960
0
        }
961
0
    }
962
0
    return 0;
963
0
}
964
965
966
/* return the length of the decomposition (length <=
967
   UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */
968
static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1)
969
0
{
970
0
    uint32_t v, type, is_compat, code, len;
971
0
    int idx_min, idx_max, idx;
972
973
0
    idx_min = 0;
974
0
    idx_max = countof(unicode_decomp_table1) - 1;
975
0
    while (idx_min <= idx_max) {
976
0
        idx = (idx_max + idx_min) / 2;
977
0
        v = unicode_decomp_table1[idx];
978
0
        code = v >> (32 - 18);
979
0
        len = (v >> (32 - 18 - 7)) & 0x7f;
980
        //        printf("idx=%d code=%05x len=%d\n", idx, code, len);
981
0
        if (c < code) {
982
0
            idx_max = idx - 1;
983
0
        } else if (c >= code + len) {
984
0
            idx_min = idx + 1;
985
0
        } else {
986
0
            is_compat = v & 1;
987
0
            if (is_compat1 < is_compat)
988
0
                break;
989
0
            type = (v >> (32 - 18 - 7 - 6)) & 0x3f;
990
0
            return unicode_decomp_entry(res, c, idx, code, len, type);
991
0
        }
992
0
    }
993
0
    return 0;
994
0
}
995
996
/* return 0 if no pair found */
997
static int unicode_compose_pair(uint32_t c0, uint32_t c1)
998
0
{
999
0
    uint32_t code, len, type, v, idx1, d_idx, d_offset, ch;
1000
0
    int idx_min, idx_max, idx, d;
1001
0
    uint32_t pair[2];
1002
1003
0
    idx_min = 0;
1004
0
    idx_max = countof(unicode_comp_table) - 1;
1005
0
    while (idx_min <= idx_max) {
1006
0
        idx = (idx_max + idx_min) / 2;
1007
0
        idx1 = unicode_comp_table[idx];
1008
1009
        /* idx1 represent an entry of the decomposition table */
1010
0
        d_idx = idx1 >> 6;
1011
0
        d_offset = idx1 & 0x3f;
1012
0
        v = unicode_decomp_table1[d_idx];
1013
0
        code = v >> (32 - 18);
1014
0
        len = (v >> (32 - 18 - 7)) & 0x7f;
1015
0
        type = (v >> (32 - 18 - 7 - 6)) & 0x3f;
1016
0
        ch = code + d_offset;
1017
0
        unicode_decomp_entry(pair, ch, d_idx, code, len, type);
1018
0
        d = c0 - pair[0];
1019
0
        if (d == 0)
1020
0
            d = c1 - pair[1];
1021
0
        if (d < 0) {
1022
0
            idx_max = idx - 1;
1023
0
        } else if (d > 0) {
1024
0
            idx_min = idx + 1;
1025
0
        } else {
1026
0
            return ch;
1027
0
        }
1028
0
    }
1029
0
    return 0;
1030
0
}
1031
1032
/* return the combining class of character c (between 0 and 255) */
1033
static int unicode_get_cc(uint32_t c)
1034
0
{
1035
0
    uint32_t code, n, type, cc, c1, b;
1036
0
    int pos;
1037
0
    const uint8_t *p;
1038
1039
0
    pos = get_index_pos(&code, c,
1040
0
                        unicode_cc_index, sizeof(unicode_cc_index) / 3);
1041
0
    if (pos < 0)
1042
0
        return 0;
1043
0
    p = unicode_cc_table + pos;
1044
    /* Compressed run length encoding:
1045
       - 2 high order bits are combining class type
1046
       -         0:0, 1:230, 2:extra byte linear progression, 3:extra byte
1047
       - 00..2F: range length (add 1)
1048
       - 30..37: 3-bit range-length + 1 extra byte
1049
       - 38..3F: 3-bit range-length + 2 extra byte
1050
     */
1051
0
    for(;;) {
1052
0
        b = *p++;
1053
0
        type = b >> 6;
1054
0
        n = b & 0x3f;
1055
0
        if (n < 48) {
1056
0
        } else if (n < 56) {
1057
0
            n = (n - 48) << 8;
1058
0
            n |= *p++;
1059
0
            n += 48;
1060
0
        } else {
1061
0
            n = (n - 56) << 8;
1062
0
            n |= *p++ << 8;
1063
0
            n |= *p++;
1064
0
            n += 48 + (1 << 11);
1065
0
        }
1066
0
        if (type <= 1)
1067
0
            p++;
1068
0
        c1 = code + n + 1;
1069
0
        if (c < c1) {
1070
0
            switch(type) {
1071
0
            case 0:
1072
0
                cc = p[-1];
1073
0
                break;
1074
0
            case 1:
1075
0
                cc = p[-1] + c - code;
1076
0
                break;
1077
0
            case 2:
1078
0
                cc = 0;
1079
0
                break;
1080
0
            default:
1081
0
            case 3:
1082
0
                cc = 230;
1083
0
                break;
1084
0
            }
1085
0
            return cc;
1086
0
        }
1087
0
        code = c1;
1088
0
    }
1089
0
}
1090
1091
static void sort_cc(int *buf, int len)
1092
0
{
1093
0
    int i, j, k, cc, cc1, start, ch1;
1094
1095
0
    for(i = 0; i < len; i++) {
1096
0
        cc = unicode_get_cc(buf[i]);
1097
0
        if (cc != 0) {
1098
0
            start = i;
1099
0
            j = i + 1;
1100
0
            while (j < len) {
1101
0
                ch1 = buf[j];
1102
0
                cc1 = unicode_get_cc(ch1);
1103
0
                if (cc1 == 0)
1104
0
                    break;
1105
0
                k = j - 1;
1106
0
                while (k >= start) {
1107
0
                    if (unicode_get_cc(buf[k]) <= cc1)
1108
0
                        break;
1109
0
                    buf[k + 1] = buf[k];
1110
0
                    k--;
1111
0
                }
1112
0
                buf[k + 1] = ch1;
1113
0
                j++;
1114
0
            }
1115
#if 0
1116
            printf("cc:");
1117
            for(k = start; k < j; k++) {
1118
                printf(" %3d", unicode_get_cc(buf[k]));
1119
            }
1120
            printf("\n");
1121
#endif
1122
0
            i = j;
1123
0
        }
1124
0
    }
1125
0
}
1126
1127
static void to_nfd_rec(DynBuf *dbuf,
1128
                       const int *src, int src_len, int is_compat)
1129
0
{
1130
0
    uint32_t c, v;
1131
0
    int i, l;
1132
0
    uint32_t res[UNICODE_DECOMP_LEN_MAX];
1133
1134
0
    for(i = 0; i < src_len; i++) {
1135
0
        c = src[i];
1136
0
        if (c >= 0xac00 && c < 0xd7a4) {
1137
            /* Hangul decomposition */
1138
0
            c -= 0xac00;
1139
0
            dbuf_put_u32(dbuf, 0x1100 + c / 588);
1140
0
            dbuf_put_u32(dbuf, 0x1161 + (c % 588) / 28);
1141
0
            v = c % 28;
1142
0
            if (v != 0)
1143
0
                dbuf_put_u32(dbuf, 0x11a7 + v);
1144
0
        } else {
1145
0
            l = unicode_decomp_char(res, c, is_compat);
1146
0
            if (l) {
1147
0
                to_nfd_rec(dbuf, (int *)res, l, is_compat);
1148
0
            } else {
1149
0
                dbuf_put_u32(dbuf, c);
1150
0
            }
1151
0
        }
1152
0
    }
1153
0
}
1154
1155
/* return 0 if not found */
1156
static int compose_pair(uint32_t c0, uint32_t c1)
1157
0
{
1158
    /* Hangul composition */
1159
0
    if (c0 >= 0x1100 && c0 < 0x1100 + 19 &&
1160
0
        c1 >= 0x1161 && c1 < 0x1161 + 21) {
1161
0
        return 0xac00 + (c0 - 0x1100) * 588 + (c1 - 0x1161) * 28;
1162
0
    } else if (c0 >= 0xac00 && c0 < 0xac00 + 11172 &&
1163
0
               (c0 - 0xac00) % 28 == 0 &&
1164
0
               c1 >= 0x11a7 && c1 < 0x11a7 + 28) {
1165
0
        return c0 + c1 - 0x11a7;
1166
0
    } else {
1167
0
        return unicode_compose_pair(c0, c1);
1168
0
    }
1169
0
}
1170
1171
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
1172
                      UnicodeNormalizationEnum n_type,
1173
                      void *opaque, DynBufReallocFunc *realloc_func)
1174
0
{
1175
0
    int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len;
1176
0
    BOOL is_compat;
1177
0
    DynBuf dbuf_s, *dbuf = &dbuf_s;
1178
1179
0
    is_compat = n_type >> 1;
1180
1181
0
    dbuf_init2(dbuf, opaque, realloc_func);
1182
0
    if (dbuf_claim(dbuf, sizeof(int) * src_len))
1183
0
        goto fail;
1184
1185
    /* common case: latin1 is unaffected by NFC */
1186
0
    if (n_type == UNICODE_NFC) {
1187
0
        for(i = 0; i < src_len; i++) {
1188
0
            if (src[i] >= 0x100)
1189
0
                goto not_latin1;
1190
0
        }
1191
0
        buf = (int *)dbuf->buf;
1192
0
        if (src_len != 0)
1193
0
            memcpy(buf, src, src_len * sizeof(int));
1194
0
        *pdst = (uint32_t *)buf;
1195
0
        return src_len;
1196
0
    not_latin1: ;
1197
0
    }
1198
1199
0
    to_nfd_rec(dbuf, (const int *)src, src_len, is_compat);
1200
0
    if (dbuf_error(dbuf)) {
1201
0
    fail:
1202
0
        *pdst = NULL;
1203
0
        return -1;
1204
0
    }
1205
0
    buf = (int *)dbuf->buf;
1206
0
    buf_len = dbuf->size / sizeof(int);
1207
1208
0
    sort_cc(buf, buf_len);
1209
1210
0
    if (buf_len <= 1 || (n_type & 1) != 0) {
1211
        /* NFD / NFKD */
1212
0
        *pdst = (uint32_t *)buf;
1213
0
        return buf_len;
1214
0
    }
1215
1216
0
    i = 1;
1217
0
    out_len = 1;
1218
0
    while (i < buf_len) {
1219
        /* find the starter character and test if it is blocked from
1220
           the character at 'i' */
1221
0
        last_cc = unicode_get_cc(buf[i]);
1222
0
        starter_pos = out_len - 1;
1223
0
        while (starter_pos >= 0) {
1224
0
            cc = unicode_get_cc(buf[starter_pos]);
1225
0
            if (cc == 0)
1226
0
                break;
1227
0
            if (cc >= last_cc)
1228
0
                goto next;
1229
0
            last_cc = 256;
1230
0
            starter_pos--;
1231
0
        }
1232
0
        if (starter_pos >= 0 &&
1233
0
            (p = compose_pair(buf[starter_pos], buf[i])) != 0) {
1234
0
            buf[starter_pos] = p;
1235
0
            i++;
1236
0
        } else {
1237
0
        next:
1238
0
            buf[out_len++] = buf[i++];
1239
0
        }
1240
0
    }
1241
0
    *pdst = (uint32_t *)buf;
1242
0
    return out_len;
1243
0
}
1244
1245
/* char ranges for various unicode properties */
1246
1247
static int unicode_find_name(const char *name_table, const char *name)
1248
0
{
1249
0
    const char *p, *r;
1250
0
    int pos;
1251
0
    size_t name_len, len;
1252
1253
0
    p = name_table;
1254
0
    pos = 0;
1255
0
    name_len = strlen(name);
1256
0
    while (*p) {
1257
0
        for(;;) {
1258
0
            r = strchr(p, ',');
1259
0
            if (!r)
1260
0
                len = strlen(p);
1261
0
            else
1262
0
                len = r - p;
1263
0
            if (len == name_len && !memcmp(p, name, name_len))
1264
0
                return pos;
1265
0
            p += len + 1;
1266
0
            if (!r)
1267
0
                break;
1268
0
        }
1269
0
        pos++;
1270
0
    }
1271
0
    return -1;
1272
0
}
1273
1274
/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2
1275
   if not found */
1276
int unicode_script(CharRange *cr,
1277
                   const char *script_name, BOOL is_ext)
1278
0
{
1279
0
    int script_idx;
1280
0
    const uint8_t *p, *p_end;
1281
0
    uint32_t c, c1, b, n, v, v_len, i, type;
1282
0
    CharRange cr1_s, *cr1;
1283
0
    CharRange cr2_s, *cr2 = &cr2_s;
1284
0
    BOOL is_common;
1285
1286
0
    script_idx = unicode_find_name(unicode_script_name_table, script_name);
1287
0
    if (script_idx < 0)
1288
0
        return -2;
1289
1290
0
    is_common = (script_idx == UNICODE_SCRIPT_Common ||
1291
0
                 script_idx == UNICODE_SCRIPT_Inherited);
1292
0
    if (is_ext) {
1293
0
        cr1 = &cr1_s;
1294
0
        cr_init(cr1, cr->mem_opaque, cr->realloc_func);
1295
0
        cr_init(cr2, cr->mem_opaque, cr->realloc_func);
1296
0
    } else {
1297
0
        cr1 = cr;
1298
0
    }
1299
1300
0
    p = unicode_script_table;
1301
0
    p_end = unicode_script_table + countof(unicode_script_table);
1302
0
    c = 0;
1303
0
    while (p < p_end) {
1304
0
        b = *p++;
1305
0
        type = b >> 7;
1306
0
        n = b & 0x7f;
1307
0
        if (n < 96) {
1308
0
        } else if (n < 112) {
1309
0
            n = (n - 96) << 8;
1310
0
            n |= *p++;
1311
0
            n += 96;
1312
0
        } else {
1313
0
            n = (n - 112) << 16;
1314
0
            n |= *p++ << 8;
1315
0
            n |= *p++;
1316
0
            n += 96 + (1 << 12);
1317
0
        }
1318
0
        c1 = c + n + 1;
1319
0
        if (type != 0) {
1320
0
            v = *p++;
1321
0
            if (v == script_idx || script_idx == UNICODE_SCRIPT_Unknown) {
1322
0
                if (cr_add_interval(cr1, c, c1))
1323
0
                    goto fail;
1324
0
            }
1325
0
        }
1326
0
        c = c1;
1327
0
    }
1328
0
    if (script_idx == UNICODE_SCRIPT_Unknown) {
1329
        /* Unknown is all the characters outside scripts */
1330
0
        if (cr_invert(cr1))
1331
0
            goto fail;
1332
0
    }
1333
1334
0
    if (is_ext) {
1335
        /* add the script extensions */
1336
0
        p = unicode_script_ext_table;
1337
0
        p_end = unicode_script_ext_table + countof(unicode_script_ext_table);
1338
0
        c = 0;
1339
0
        while (p < p_end) {
1340
0
            b = *p++;
1341
0
            if (b < 128) {
1342
0
                n = b;
1343
0
            } else if (b < 128 + 64) {
1344
0
                n = (b - 128) << 8;
1345
0
                n |= *p++;
1346
0
                n += 128;
1347
0
            } else {
1348
0
                n = (b - 128 - 64) << 16;
1349
0
                n |= *p++ << 8;
1350
0
                n |= *p++;
1351
0
                n += 128 + (1 << 14);
1352
0
            }
1353
0
            c1 = c + n + 1;
1354
0
            v_len = *p++;
1355
0
            if (is_common) {
1356
0
                if (v_len != 0) {
1357
0
                    if (cr_add_interval(cr2, c, c1))
1358
0
                        goto fail;
1359
0
                }
1360
0
            } else {
1361
0
                for(i = 0; i < v_len; i++) {
1362
0
                    if (p[i] == script_idx) {
1363
0
                        if (cr_add_interval(cr2, c, c1))
1364
0
                            goto fail;
1365
0
                        break;
1366
0
                    }
1367
0
                }
1368
0
            }
1369
0
            p += v_len;
1370
0
            c = c1;
1371
0
        }
1372
0
        if (is_common) {
1373
            /* remove all the characters with script extensions */
1374
0
            if (cr_invert(cr2))
1375
0
                goto fail;
1376
0
            if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len,
1377
0
                      CR_OP_INTER))
1378
0
                goto fail;
1379
0
        } else {
1380
0
            if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len,
1381
0
                      CR_OP_UNION))
1382
0
                goto fail;
1383
0
        }
1384
0
        cr_free(cr1);
1385
0
        cr_free(cr2);
1386
0
    }
1387
0
    return 0;
1388
0
 fail:
1389
0
    if (is_ext) {
1390
0
        cr_free(cr1);
1391
0
        cr_free(cr2);
1392
0
    }
1393
0
    goto fail;
1394
0
}
1395
1396
0
#define M(id) (1U << UNICODE_GC_ ## id)
1397
1398
static int unicode_general_category1(CharRange *cr, uint32_t gc_mask)
1399
0
{
1400
0
    const uint8_t *p, *p_end;
1401
0
    uint32_t c, c0, b, n, v;
1402
1403
0
    p = unicode_gc_table;
1404
0
    p_end = unicode_gc_table + countof(unicode_gc_table);
1405
0
    c = 0;
1406
    /* Compressed range encoding:
1407
       initial byte:
1408
       bits 0..4: category number (special case 31)
1409
       bits 5..7: range length (add 1)
1410
       special case bits 5..7 == 7: read an extra byte
1411
       - 00..7F: range length (add 7 + 1)
1412
       - 80..BF: 6-bits plus extra byte for range length (add 7 + 128)
1413
       - C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384)
1414
     */
1415
0
    while (p < p_end) {
1416
0
        b = *p++;
1417
0
        n = b >> 5;
1418
0
        v = b & 0x1f;
1419
0
        if (n == 7) {
1420
0
            n = *p++;
1421
0
            if (n < 128) {
1422
0
                n += 7;
1423
0
            } else if (n < 128 + 64) {
1424
0
                n = (n - 128) << 8;
1425
0
                n |= *p++;
1426
0
                n += 7 + 128;
1427
0
            } else {
1428
0
                n = (n - 128 - 64) << 16;
1429
0
                n |= *p++ << 8;
1430
0
                n |= *p++;
1431
0
                n += 7 + 128 + (1 << 14);
1432
0
            }
1433
0
        }
1434
0
        c0 = c;
1435
0
        c += n + 1;
1436
0
        if (v == 31) {
1437
            /* run of Lu / Ll */
1438
0
            b = gc_mask & (M(Lu) | M(Ll));
1439
0
            if (b != 0) {
1440
0
                if (b == (M(Lu) | M(Ll))) {
1441
0
                    goto add_range;
1442
0
                } else {
1443
0
                    c0 += ((gc_mask & M(Ll)) != 0);
1444
0
                    for(; c0 < c; c0 += 2) {
1445
0
                        if (cr_add_interval(cr, c0, c0 + 1))
1446
0
                            return -1;
1447
0
                    }
1448
0
                }
1449
0
            }
1450
0
        } else if ((gc_mask >> v) & 1) {
1451
0
        add_range:
1452
0
            if (cr_add_interval(cr, c0, c))
1453
0
                return -1;
1454
0
        }
1455
0
    }
1456
0
    return 0;
1457
0
}
1458
1459
static int unicode_prop1(CharRange *cr, int prop_idx)
1460
0
{
1461
0
    const uint8_t *p, *p_end;
1462
0
    uint32_t c, c0, b, bit;
1463
1464
0
    p = unicode_prop_table[prop_idx];
1465
0
    p_end = p + unicode_prop_len_table[prop_idx];
1466
0
    c = 0;
1467
0
    bit = 0;
1468
    /* Compressed range encoding:
1469
       00..3F: 2 packed lengths: 3-bit + 3-bit
1470
       40..5F: 5-bits plus extra byte for length
1471
       60..7F: 5-bits plus 2 extra bytes for length
1472
       80..FF: 7-bit length
1473
       lengths must be incremented to get character count
1474
       Ranges alternate between false and true return value.
1475
     */
1476
0
    while (p < p_end) {
1477
0
        c0 = c;
1478
0
        b = *p++;
1479
0
        if (b < 64) {
1480
0
            c += (b >> 3) + 1;
1481
0
            if (bit)  {
1482
0
                if (cr_add_interval(cr, c0, c))
1483
0
                    return -1;
1484
0
            }
1485
0
            bit ^= 1;
1486
0
            c0 = c;
1487
0
            c += (b & 7) + 1;
1488
0
        } else if (b >= 0x80) {
1489
0
            c += b - 0x80 + 1;
1490
0
        } else if (b < 0x60) {
1491
0
            c += (((b - 0x40) << 8) | p[0]) + 1;
1492
0
            p++;
1493
0
        } else {
1494
0
            c += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1;
1495
0
            p += 2;
1496
0
        }
1497
0
        if (bit)  {
1498
0
            if (cr_add_interval(cr, c0, c))
1499
0
                return -1;
1500
0
        }
1501
0
        bit ^= 1;
1502
0
    }
1503
0
    return 0;
1504
0
}
1505
1506
typedef enum {
1507
    POP_GC,
1508
    POP_PROP,
1509
    POP_CASE,
1510
    POP_UNION,
1511
    POP_INTER,
1512
    POP_XOR,
1513
    POP_INVERT,
1514
    POP_END,
1515
} PropOPEnum;
1516
1517
#define POP_STACK_LEN_MAX 4
1518
1519
static int unicode_prop_ops(CharRange *cr, ...)
1520
0
{
1521
0
    va_list ap;
1522
0
    CharRange stack[POP_STACK_LEN_MAX];
1523
0
    int stack_len, op, ret, i;
1524
0
    uint32_t a;
1525
1526
0
    va_start(ap, cr);
1527
0
    stack_len = 0;
1528
0
    for(;;) {
1529
0
        op = va_arg(ap, int);
1530
0
        switch(op) {
1531
0
        case POP_GC:
1532
0
            assert(stack_len < POP_STACK_LEN_MAX);
1533
0
            a = va_arg(ap, int);
1534
0
            cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);
1535
0
            if (unicode_general_category1(&stack[stack_len - 1], a))
1536
0
                goto fail;
1537
0
            break;
1538
0
        case POP_PROP:
1539
0
            assert(stack_len < POP_STACK_LEN_MAX);
1540
0
            a = va_arg(ap, int);
1541
0
            cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);
1542
0
            if (unicode_prop1(&stack[stack_len - 1], a))
1543
0
                goto fail;
1544
0
            break;
1545
0
        case POP_CASE:
1546
0
            assert(stack_len < POP_STACK_LEN_MAX);
1547
0
            a = va_arg(ap, int);
1548
0
            cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);
1549
0
            if (unicode_case1(&stack[stack_len - 1], a))
1550
0
                goto fail;
1551
0
            break;
1552
0
        case POP_UNION:
1553
0
        case POP_INTER:
1554
0
        case POP_XOR:
1555
0
            {
1556
0
                CharRange *cr1, *cr2, *cr3;
1557
0
                assert(stack_len >= 2);
1558
0
                assert(stack_len < POP_STACK_LEN_MAX);
1559
0
                cr1 = &stack[stack_len - 2];
1560
0
                cr2 = &stack[stack_len - 1];
1561
0
                cr3 = &stack[stack_len++];
1562
0
                cr_init(cr3, cr->mem_opaque, cr->realloc_func);
1563
                /* CR_OP_XOR may be used here */
1564
0
                if (cr_op(cr3, cr1->points, cr1->len,
1565
0
                          cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION))
1566
0
                    goto fail;
1567
0
                cr_free(cr1);
1568
0
                cr_free(cr2);
1569
0
                *cr1 = *cr3;
1570
0
                stack_len -= 2;
1571
0
            }
1572
0
            break;
1573
0
        case POP_INVERT:
1574
0
            assert(stack_len >= 1);
1575
0
            if (cr_invert(&stack[stack_len - 1]))
1576
0
                goto fail;
1577
0
            break;
1578
0
        case POP_END:
1579
0
            goto done;
1580
0
        default:
1581
0
            abort();
1582
0
        }
1583
0
    }
1584
0
 done:
1585
0
    assert(stack_len == 1);
1586
0
    ret = cr_copy(cr, &stack[0]);
1587
0
    cr_free(&stack[0]);
1588
0
    return ret;
1589
0
 fail:
1590
0
    for(i = 0; i < stack_len; i++)
1591
0
        cr_free(&stack[i]);
1592
0
    return -1;
1593
0
}
1594
1595
static const uint32_t unicode_gc_mask_table[] = {
1596
    M(Lu) | M(Ll) | M(Lt), /* LC */
1597
    M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo), /* L */
1598
    M(Mn) | M(Mc) | M(Me), /* M */
1599
    M(Nd) | M(Nl) | M(No), /* N */
1600
    M(Sm) | M(Sc) | M(Sk) | M(So), /* S */
1601
    M(Pc) | M(Pd) | M(Ps) | M(Pe) | M(Pi) | M(Pf) | M(Po), /* P */
1602
    M(Zs) | M(Zl) | M(Zp), /* Z */
1603
    M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn), /* C */
1604
};
1605
1606
/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2
1607
   if not found */
1608
int unicode_general_category(CharRange *cr, const char *gc_name)
1609
0
{
1610
0
    int gc_idx;
1611
0
    uint32_t gc_mask;
1612
1613
0
    gc_idx = unicode_find_name(unicode_gc_name_table, gc_name);
1614
0
    if (gc_idx < 0)
1615
0
        return -2;
1616
0
    if (gc_idx <= UNICODE_GC_Co) {
1617
0
        gc_mask = (uint64_t)1 << gc_idx;
1618
0
    } else {
1619
0
        gc_mask = unicode_gc_mask_table[gc_idx - UNICODE_GC_LC];
1620
0
    }
1621
0
    return unicode_general_category1(cr, gc_mask);
1622
0
}
1623
1624
1625
/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2
1626
   if not found */
1627
int unicode_prop(CharRange *cr, const char *prop_name)
1628
0
{
1629
0
    int prop_idx, ret;
1630
1631
0
    prop_idx = unicode_find_name(unicode_prop_name_table, prop_name);
1632
0
    if (prop_idx < 0)
1633
0
        return -2;
1634
0
    prop_idx += UNICODE_PROP_ASCII_Hex_Digit;
1635
1636
0
    ret = 0;
1637
0
    switch(prop_idx) {
1638
0
    case UNICODE_PROP_ASCII:
1639
0
        if (cr_add_interval(cr, 0x00, 0x7f + 1))
1640
0
            return -1;
1641
0
        break;
1642
0
    case UNICODE_PROP_Any:
1643
0
        if (cr_add_interval(cr, 0x00000, 0x10ffff + 1))
1644
0
            return -1;
1645
0
        break;
1646
0
    case UNICODE_PROP_Assigned:
1647
0
        ret = unicode_prop_ops(cr,
1648
0
                               POP_GC, M(Cn),
1649
0
                               POP_INVERT,
1650
0
                               POP_END);
1651
0
        break;
1652
0
    case UNICODE_PROP_Math:
1653
0
        ret = unicode_prop_ops(cr,
1654
0
                               POP_GC, M(Sm),
1655
0
                               POP_PROP, UNICODE_PROP_Other_Math,
1656
0
                               POP_UNION,
1657
0
                               POP_END);
1658
0
        break;
1659
0
    case UNICODE_PROP_Lowercase:
1660
0
        ret = unicode_prop_ops(cr,
1661
0
                               POP_GC, M(Ll),
1662
0
                               POP_PROP, UNICODE_PROP_Other_Lowercase,
1663
0
                               POP_UNION,
1664
0
                               POP_END);
1665
0
        break;
1666
0
    case UNICODE_PROP_Uppercase:
1667
0
        ret = unicode_prop_ops(cr,
1668
0
                               POP_GC, M(Lu),
1669
0
                               POP_PROP, UNICODE_PROP_Other_Uppercase,
1670
0
                               POP_UNION,
1671
0
                               POP_END);
1672
0
        break;
1673
0
    case UNICODE_PROP_Cased:
1674
0
        ret = unicode_prop_ops(cr,
1675
0
                               POP_GC, M(Lu) | M(Ll) | M(Lt),
1676
0
                               POP_PROP, UNICODE_PROP_Other_Uppercase,
1677
0
                               POP_UNION,
1678
0
                               POP_PROP, UNICODE_PROP_Other_Lowercase,
1679
0
                               POP_UNION,
1680
0
                               POP_END);
1681
0
        break;
1682
0
    case UNICODE_PROP_Alphabetic:
1683
0
        ret = unicode_prop_ops(cr,
1684
0
                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),
1685
0
                               POP_PROP, UNICODE_PROP_Other_Uppercase,
1686
0
                               POP_UNION,
1687
0
                               POP_PROP, UNICODE_PROP_Other_Lowercase,
1688
0
                               POP_UNION,
1689
0
                               POP_PROP, UNICODE_PROP_Other_Alphabetic,
1690
0
                               POP_UNION,
1691
0
                               POP_END);
1692
0
        break;
1693
0
    case UNICODE_PROP_Grapheme_Base:
1694
0
        ret = unicode_prop_ops(cr,
1695
0
                               POP_GC, M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn) | M(Zl) | M(Zp) | M(Me) | M(Mn),
1696
0
                               POP_PROP, UNICODE_PROP_Other_Grapheme_Extend,
1697
0
                               POP_UNION,
1698
0
                               POP_INVERT,
1699
0
                               POP_END);
1700
0
        break;
1701
0
    case UNICODE_PROP_Grapheme_Extend:
1702
0
        ret = unicode_prop_ops(cr,
1703
0
                               POP_GC, M(Me) | M(Mn),
1704
0
                               POP_PROP, UNICODE_PROP_Other_Grapheme_Extend,
1705
0
                               POP_UNION,
1706
0
                               POP_END);
1707
0
        break;
1708
0
    case UNICODE_PROP_XID_Start:
1709
0
        ret = unicode_prop_ops(cr,
1710
0
                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),
1711
0
                               POP_PROP, UNICODE_PROP_Other_ID_Start,
1712
0
                               POP_UNION,
1713
0
                               POP_PROP, UNICODE_PROP_Pattern_Syntax,
1714
0
                               POP_PROP, UNICODE_PROP_Pattern_White_Space,
1715
0
                               POP_UNION,
1716
0
                               POP_PROP, UNICODE_PROP_XID_Start1,
1717
0
                               POP_UNION,
1718
0
                               POP_INVERT,
1719
0
                               POP_INTER,
1720
0
                               POP_END);
1721
0
        break;
1722
0
    case UNICODE_PROP_XID_Continue:
1723
0
        ret = unicode_prop_ops(cr,
1724
0
                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) |
1725
0
                               M(Mn) | M(Mc) | M(Nd) | M(Pc),
1726
0
                               POP_PROP, UNICODE_PROP_Other_ID_Start,
1727
0
                               POP_UNION,
1728
0
                               POP_PROP, UNICODE_PROP_Other_ID_Continue,
1729
0
                               POP_UNION,
1730
0
                               POP_PROP, UNICODE_PROP_Pattern_Syntax,
1731
0
                               POP_PROP, UNICODE_PROP_Pattern_White_Space,
1732
0
                               POP_UNION,
1733
0
                               POP_PROP, UNICODE_PROP_XID_Continue1,
1734
0
                               POP_UNION,
1735
0
                               POP_INVERT,
1736
0
                               POP_INTER,
1737
0
                               POP_END);
1738
0
        break;
1739
0
    case UNICODE_PROP_Changes_When_Uppercased:
1740
0
        ret = unicode_case1(cr, CASE_U);
1741
0
        break;
1742
0
    case UNICODE_PROP_Changes_When_Lowercased:
1743
0
        ret = unicode_case1(cr, CASE_L);
1744
0
        break;
1745
0
    case UNICODE_PROP_Changes_When_Casemapped:
1746
0
        ret = unicode_case1(cr, CASE_U | CASE_L | CASE_F);
1747
0
        break;
1748
0
    case UNICODE_PROP_Changes_When_Titlecased:
1749
0
        ret = unicode_prop_ops(cr,
1750
0
                               POP_CASE, CASE_U,
1751
0
                               POP_PROP, UNICODE_PROP_Changes_When_Titlecased1,
1752
0
                               POP_XOR,
1753
0
                               POP_END);
1754
0
        break;
1755
0
    case UNICODE_PROP_Changes_When_Casefolded:
1756
0
        ret = unicode_prop_ops(cr,
1757
0
                               POP_CASE, CASE_F,
1758
0
                               POP_PROP, UNICODE_PROP_Changes_When_Casefolded1,
1759
0
                               POP_XOR,
1760
0
                               POP_END);
1761
0
        break;
1762
0
    case UNICODE_PROP_Changes_When_NFKC_Casefolded:
1763
0
        ret = unicode_prop_ops(cr,
1764
0
                               POP_CASE, CASE_F,
1765
0
                               POP_PROP, UNICODE_PROP_Changes_When_NFKC_Casefolded1,
1766
0
                               POP_XOR,
1767
0
                               POP_END);
1768
0
        break;
1769
#if 0
1770
    case UNICODE_PROP_ID_Start:
1771
        ret = unicode_prop_ops(cr,
1772
                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),
1773
                               POP_PROP, UNICODE_PROP_Other_ID_Start,
1774
                               POP_UNION,
1775
                               POP_PROP, UNICODE_PROP_Pattern_Syntax,
1776
                               POP_PROP, UNICODE_PROP_Pattern_White_Space,
1777
                               POP_UNION,
1778
                               POP_INVERT,
1779
                               POP_INTER,
1780
                               POP_END);
1781
        break;
1782
    case UNICODE_PROP_ID_Continue:
1783
        ret = unicode_prop_ops(cr,
1784
                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) |
1785
                               M(Mn) | M(Mc) | M(Nd) | M(Pc),
1786
                               POP_PROP, UNICODE_PROP_Other_ID_Start,
1787
                               POP_UNION,
1788
                               POP_PROP, UNICODE_PROP_Other_ID_Continue,
1789
                               POP_UNION,
1790
                               POP_PROP, UNICODE_PROP_Pattern_Syntax,
1791
                               POP_PROP, UNICODE_PROP_Pattern_White_Space,
1792
                               POP_UNION,
1793
                               POP_INVERT,
1794
                               POP_INTER,
1795
                               POP_END);
1796
        break;
1797
    case UNICODE_PROP_Case_Ignorable:
1798
        ret = unicode_prop_ops(cr,
1799
                               POP_GC, M(Mn) | M(Cf) | M(Lm) | M(Sk),
1800
                               POP_PROP, UNICODE_PROP_Case_Ignorable1,
1801
                               POP_XOR,
1802
                               POP_END);
1803
        break;
1804
#else
1805
        /* we use the existing tables */
1806
0
    case UNICODE_PROP_ID_Continue:
1807
0
        ret = unicode_prop_ops(cr,
1808
0
                               POP_PROP, UNICODE_PROP_ID_Start,
1809
0
                               POP_PROP, UNICODE_PROP_ID_Continue1,
1810
0
                               POP_XOR,
1811
0
                               POP_END);
1812
0
        break;
1813
0
#endif
1814
0
    default:
1815
0
        if (prop_idx >= countof(unicode_prop_table))
1816
0
            return -2;
1817
0
        ret = unicode_prop1(cr, prop_idx);
1818
0
        break;
1819
0
    }
1820
0
    return ret;
1821
0
}
1822
1823
#endif /* CONFIG_ALL_UNICODE */
1824
1825
/*---- lre codepoint categorizing functions ----*/
1826
1827
#define S  UNICODE_C_SPACE
1828
#define D  UNICODE_C_DIGIT
1829
#define X  UNICODE_C_XDIGIT
1830
#define U  UNICODE_C_UPPER
1831
#define L  UNICODE_C_LOWER
1832
#define _  UNICODE_C_UNDER
1833
#define d  UNICODE_C_DOLLAR
1834
1835
uint8_t const lre_ctype_bits[256] = {
1836
    0, 0, 0, 0, 0, 0, 0, 0,
1837
    0, S, S, S, S, S, 0, 0,
1838
    0, 0, 0, 0, 0, 0, 0, 0,
1839
    0, 0, 0, 0, 0, 0, 0, 0,
1840
1841
    S, 0, 0, 0, d, 0, 0, 0,
1842
    0, 0, 0, 0, 0, 0, 0, 0,
1843
    X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D,
1844
    X|D, X|D, 0, 0, 0, 0, 0, 0,
1845
1846
    0, X|U, X|U, X|U, X|U, X|U, X|U, U,
1847
    U, U, U, U, U, U, U, U,
1848
    U, U, U, U, U, U, U, U,
1849
    U, U, U, 0, 0, 0, 0, _,
1850
1851
    0, X|L, X|L, X|L, X|L, X|L, X|L, L,
1852
    L, L, L, L, L, L, L, L,
1853
    L, L, L, L, L, L, L, L,
1854
    L, L, L, 0, 0, 0, 0, 0,
1855
1856
    0, 0, 0, 0, 0, 0, 0, 0,
1857
    0, 0, 0, 0, 0, 0, 0, 0,
1858
    0, 0, 0, 0, 0, 0, 0, 0,
1859
    0, 0, 0, 0, 0, 0, 0, 0,
1860
1861
    S, 0, 0, 0, 0, 0, 0, 0,
1862
    0, 0, 0, 0, 0, 0, 0, 0,
1863
    0, 0, 0, 0, 0, 0, 0, 0,
1864
    0, 0, 0, 0, 0, 0, 0, 0,
1865
1866
    0, 0, 0, 0, 0, 0, 0, 0,
1867
    0, 0, 0, 0, 0, 0, 0, 0,
1868
    0, 0, 0, 0, 0, 0, 0, 0,
1869
    0, 0, 0, 0, 0, 0, 0, 0,
1870
1871
    0, 0, 0, 0, 0, 0, 0, 0,
1872
    0, 0, 0, 0, 0, 0, 0, 0,
1873
    0, 0, 0, 0, 0, 0, 0, 0,
1874
    0, 0, 0, 0, 0, 0, 0, 0,
1875
};
1876
1877
#undef S
1878
#undef D
1879
#undef X
1880
#undef U
1881
#undef L
1882
#undef _
1883
#undef d
1884
1885
/* code point ranges for Zs,Zl or Zp property */
1886
static const uint16_t char_range_s[] = {
1887
    10,
1888
    0x0009, 0x000D + 1,
1889
    0x0020, 0x0020 + 1,
1890
    0x00A0, 0x00A0 + 1,
1891
    0x1680, 0x1680 + 1,
1892
    0x2000, 0x200A + 1,
1893
    /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */
1894
    /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */
1895
    0x2028, 0x2029 + 1,
1896
    0x202F, 0x202F + 1,
1897
    0x205F, 0x205F + 1,
1898
    0x3000, 0x3000 + 1,
1899
    /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */
1900
    0xFEFF, 0xFEFF + 1,
1901
};
1902
1903
BOOL lre_is_space_non_ascii(uint32_t c)
1904
8
{
1905
8
    size_t i, n;
1906
1907
8
    n = countof(char_range_s);
1908
72
    for(i = 5; i < n; i += 2) {
1909
64
        uint32_t low = char_range_s[i];
1910
64
        uint32_t high = char_range_s[i + 1];
1911
64
        if (c < low)
1912
0
            return FALSE;
1913
64
        if (c < high)
1914
0
            return TRUE;
1915
64
    }
1916
8
    return FALSE;
1917
8
}
1918
1919
#define SEQ_MAX_LEN 16
1920
1921
static int unicode_sequence_prop1(int seq_prop_idx, UnicodeSequencePropCB *cb, void *opaque,
1922
                                  CharRange *cr)
1923
0
{
1924
0
    int i, c, j;
1925
0
    uint32_t seq[SEQ_MAX_LEN];
1926
    
1927
0
    switch(seq_prop_idx) {
1928
0
    case UNICODE_SEQUENCE_PROP_Basic_Emoji:
1929
0
        if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji1) < 0)
1930
0
            return -1;
1931
0
        for(i = 0; i < cr->len; i += 2) {
1932
0
            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
1933
0
                seq[0] = c;
1934
0
                cb(opaque, seq, 1);
1935
0
            }
1936
0
        }
1937
1938
0
        cr->len = 0;
1939
1940
0
        if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji2) < 0)
1941
0
            return -1;
1942
0
        for(i = 0; i < cr->len; i += 2) {
1943
0
            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
1944
0
                seq[0] = c;
1945
0
                seq[1] = 0xfe0f;
1946
0
                cb(opaque, seq, 2);
1947
0
            }
1948
0
        }
1949
1950
0
        break;
1951
0
    case UNICODE_SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence:
1952
0
        if (unicode_prop1(cr, UNICODE_PROP_Emoji_Modifier_Base) < 0)
1953
0
            return -1;
1954
0
        for(i = 0; i < cr->len; i += 2) {
1955
0
            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
1956
0
                for(j = 0; j < 5; j++) {
1957
0
                    seq[0] = c;
1958
0
                    seq[1] = 0x1f3fb + j;
1959
0
                    cb(opaque, seq, 2);
1960
0
                }
1961
0
            }
1962
0
        }
1963
0
        break;
1964
0
    case UNICODE_SEQUENCE_PROP_RGI_Emoji_Flag_Sequence:
1965
0
        if (unicode_prop1(cr, UNICODE_PROP_RGI_Emoji_Flag_Sequence) < 0)
1966
0
            return -1;
1967
0
        for(i = 0; i < cr->len; i += 2) {
1968
0
            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
1969
0
                int c0, c1;
1970
0
                c0 = c / 26;
1971
0
                c1 = c % 26;
1972
0
                seq[0] = 0x1F1E6 + c0;
1973
0
                seq[1] = 0x1F1E6 + c1;
1974
0
                cb(opaque, seq, 2);
1975
0
            }
1976
0
        }
1977
0
        break;
1978
0
    case UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence:
1979
0
        {
1980
0
            int len, code, pres, k, mod, mod_count, mod_pos[2], hc_pos, n_mod, n_hc, mod1;
1981
0
            int mod_idx, hc_idx, i0, i1;
1982
0
            const uint8_t *tab = unicode_rgi_emoji_zwj_sequence;
1983
            
1984
0
            for(i = 0; i < countof(unicode_rgi_emoji_zwj_sequence);) {
1985
0
                len = tab[i++];
1986
0
                k = 0;
1987
0
                mod = 0;
1988
0
                mod_count = 0;
1989
0
                hc_pos = -1;
1990
0
                for(j = 0; j < len; j++) {
1991
0
                    code = tab[i++];
1992
0
                    code |= tab[i++] << 8;
1993
0
                    pres = code >> 15;
1994
0
                    mod1 = (code >> 13) & 3;
1995
0
                    code &= 0x1fff;
1996
0
                    if (code < 0x1000) {
1997
0
                        c = code + 0x2000;
1998
0
                    } else {
1999
0
                        c = 0x1f000 + (code - 0x1000);
2000
0
                    }
2001
0
                    if (c == 0x1f9b0)
2002
0
                        hc_pos = k;
2003
0
                    seq[k++] = c;
2004
0
                    if (mod1 != 0) {
2005
0
                        assert(mod_count < 2);
2006
0
                        mod = mod1;
2007
0
                        mod_pos[mod_count++] = k;
2008
0
                        seq[k++] = 0; /* will be filled later */
2009
0
                    }
2010
0
                    if (pres) {
2011
0
                        seq[k++] = 0xfe0f;
2012
0
                    }
2013
0
                    if (j < len - 1) {
2014
0
                        seq[k++] = 0x200d;
2015
0
                    }
2016
0
                }
2017
2018
                /* genrate all the variants */
2019
0
                switch(mod) {
2020
0
                case 1:
2021
0
                    n_mod = 5;
2022
0
                    break;
2023
0
                case 2:
2024
0
                    n_mod = 25;
2025
0
                    break;
2026
0
                case 3:
2027
0
                    n_mod = 20;
2028
0
                    break;
2029
0
                default:
2030
0
                    n_mod = 1;
2031
0
                    break;
2032
0
                }
2033
0
                if (hc_pos >= 0)
2034
0
                    n_hc = 4;
2035
0
                else
2036
0
                    n_hc = 1;
2037
0
                for(hc_idx = 0; hc_idx < n_hc; hc_idx++) {
2038
0
                    for(mod_idx = 0; mod_idx < n_mod; mod_idx++) {
2039
0
                        if (hc_pos >= 0)
2040
0
                            seq[hc_pos] = 0x1f9b0 + hc_idx;
2041
                        
2042
0
                        switch(mod) {
2043
0
                        case 1:
2044
0
                            seq[mod_pos[0]] = 0x1f3fb + mod_idx;
2045
0
                            break;
2046
0
                        case 2:
2047
0
                        case 3:
2048
0
                            i0 = mod_idx / 5;
2049
0
                            i1 = mod_idx % 5;
2050
                            /* avoid identical values */
2051
0
                            if (mod == 3 && i0 >= i1)
2052
0
                                i0++;
2053
0
                            seq[mod_pos[0]] = 0x1f3fb + i0;
2054
0
                            seq[mod_pos[1]] = 0x1f3fb + i1;
2055
0
                            break;
2056
0
                        default:
2057
0
                            break;
2058
0
                        }
2059
#if 0
2060
                        for(j = 0; j < k; j++)
2061
                            printf(" %04x", seq[j]);
2062
                        printf("\n");
2063
#endif                
2064
0
                        cb(opaque, seq, k);
2065
0
                    }
2066
0
                }
2067
0
            }
2068
0
        }
2069
0
        break;
2070
0
    case UNICODE_SEQUENCE_PROP_RGI_Emoji_Tag_Sequence:
2071
0
        {
2072
0
            for(i = 0; i < countof(unicode_rgi_emoji_tag_sequence);) {
2073
0
                j = 0;
2074
0
                seq[j++] = 0x1F3F4;
2075
0
                for(;;) {
2076
0
                    c = unicode_rgi_emoji_tag_sequence[i++];
2077
0
                    if (c == 0x00)
2078
0
                        break;
2079
0
                    seq[j++] = 0xe0000 + c;
2080
0
                }
2081
0
                seq[j++] = 0xe007f;
2082
0
                cb(opaque, seq, j);
2083
0
            }
2084
0
        }
2085
0
        break;
2086
0
    case UNICODE_SEQUENCE_PROP_Emoji_Keycap_Sequence:
2087
0
        if (unicode_prop1(cr, UNICODE_PROP_Emoji_Keycap_Sequence) < 0)
2088
0
            return -1;
2089
0
        for(i = 0; i < cr->len; i += 2) {
2090
0
            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {
2091
0
                seq[0] = c;
2092
0
                seq[1] = 0xfe0f;
2093
0
                seq[2] = 0x20e3;
2094
0
                cb(opaque, seq, 3);
2095
0
            }
2096
0
        }
2097
0
        break;
2098
0
    case UNICODE_SEQUENCE_PROP_RGI_Emoji:
2099
        /* all prevous sequences */
2100
0
        for(i = UNICODE_SEQUENCE_PROP_Basic_Emoji; i <= UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence; i++) {
2101
0
            int ret;
2102
0
            ret = unicode_sequence_prop1(i, cb, opaque, cr);
2103
0
            if (ret < 0)
2104
0
                return ret;
2105
0
            cr->len = 0;
2106
0
        }
2107
0
        break;
2108
0
    default:
2109
0
        return -2;
2110
0
    }
2111
0
    return 0;
2112
0
}
2113
2114
/* build a unicode sequence property */
2115
/* return -2 if not found, -1 if other error. 'cr' is used as temporary memory. */
2116
int unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque,
2117
                          CharRange *cr)
2118
0
{
2119
0
    int seq_prop_idx;
2120
0
    seq_prop_idx = unicode_find_name(unicode_sequence_prop_name_table, prop_name);
2121
0
    if (seq_prop_idx < 0)
2122
0
        return -2;
2123
0
    return unicode_sequence_prop1(seq_prop_idx, cb, opaque, cr);
2124
0
}