Coverage Report

Created: 2025-06-13 06:34

/src/icu/icu4c/source/common/ucptrie.cpp
Line
Count
Source (jump to first uncovered line)
1
// © 2017 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
4
// ucptrie.cpp (modified from utrie2.cpp)
5
// created: 2017dec29 Markus W. Scherer
6
7
// #define UCPTRIE_DEBUG
8
#ifdef UCPTRIE_DEBUG
9
#   include <stdio.h>
10
#endif
11
12
#include "unicode/utypes.h"
13
#include "unicode/ucptrie.h"
14
#include "unicode/utf.h"
15
#include "unicode/utf8.h"
16
#include "unicode/utf16.h"
17
#include "cmemory.h"
18
#include "uassert.h"
19
#include "ucptrie_impl.h"
20
21
U_CAPI UCPTrie * U_EXPORT2
22
ucptrie_openFromBinary(UCPTrieType type, UCPTrieValueWidth valueWidth,
23
                       const void *data, int32_t length, int32_t *pActualLength,
24
6
                       UErrorCode *pErrorCode) {
25
6
    if (U_FAILURE(*pErrorCode)) {
26
0
        return nullptr;
27
0
    }
28
29
6
    if (length <= 0 || (U_POINTER_MASK_LSB(data, 3) != 0) ||
30
6
            type < UCPTRIE_TYPE_ANY || UCPTRIE_TYPE_SMALL < type ||
31
6
            valueWidth < UCPTRIE_VALUE_BITS_ANY || UCPTRIE_VALUE_BITS_8 < valueWidth) {
32
0
        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
33
0
        return nullptr;
34
0
    }
35
36
    // Enough data for a trie header?
37
6
    if (length < (int32_t)sizeof(UCPTrieHeader)) {
38
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
39
0
        return nullptr;
40
0
    }
41
42
    // Check the signature.
43
6
    const UCPTrieHeader *header = (const UCPTrieHeader *)data;
44
6
    if (header->signature != UCPTRIE_SIG) {
45
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
46
0
        return nullptr;
47
0
    }
48
49
6
    int32_t options = header->options;
50
6
    int32_t typeInt = (options >> 6) & 3;
51
6
    int32_t valueWidthInt = options & UCPTRIE_OPTIONS_VALUE_BITS_MASK;
52
6
    if (typeInt > UCPTRIE_TYPE_SMALL || valueWidthInt > UCPTRIE_VALUE_BITS_8 ||
53
6
            (options & UCPTRIE_OPTIONS_RESERVED_MASK) != 0) {
54
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
55
0
        return nullptr;
56
0
    }
57
6
    UCPTrieType actualType = (UCPTrieType)typeInt;
58
6
    UCPTrieValueWidth actualValueWidth = (UCPTrieValueWidth)valueWidthInt;
59
6
    if (type < 0) {
60
3
        type = actualType;
61
3
    }
62
6
    if (valueWidth < 0) {
63
3
        valueWidth = actualValueWidth;
64
3
    }
65
6
    if (type != actualType || valueWidth != actualValueWidth) {
66
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
67
0
        return nullptr;
68
0
    }
69
70
    // Get the length values and offsets.
71
6
    UCPTrie tempTrie;
72
6
    uprv_memset(&tempTrie, 0, sizeof(tempTrie));
73
6
    tempTrie.indexLength = header->indexLength;
74
6
    tempTrie.dataLength =
75
6
        ((options & UCPTRIE_OPTIONS_DATA_LENGTH_MASK) << 4) | header->dataLength;
76
6
    tempTrie.index3NullOffset = header->index3NullOffset;
77
6
    tempTrie.dataNullOffset =
78
6
        ((options & UCPTRIE_OPTIONS_DATA_NULL_OFFSET_MASK) << 8) | header->dataNullOffset;
79
80
6
    tempTrie.highStart = header->shiftedHighStart << UCPTRIE_SHIFT_2;
81
6
    tempTrie.shifted12HighStart = (tempTrie.highStart + 0xfff) >> 12;
82
6
    tempTrie.type = type;
83
6
    tempTrie.valueWidth = valueWidth;
84
85
    // Calculate the actual length.
86
6
    int32_t actualLength = (int32_t)sizeof(UCPTrieHeader) + tempTrie.indexLength * 2;
87
6
    if (valueWidth == UCPTRIE_VALUE_BITS_16) {
88
2
        actualLength += tempTrie.dataLength * 2;
89
4
    } else if (valueWidth == UCPTRIE_VALUE_BITS_32) {
90
0
        actualLength += tempTrie.dataLength * 4;
91
4
    } else {
92
4
        actualLength += tempTrie.dataLength;
93
4
    }
94
6
    if (length < actualLength) {
95
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;  // Not enough bytes.
96
0
        return nullptr;
97
0
    }
98
99
    // Allocate the trie.
100
6
    UCPTrie *trie = (UCPTrie *)uprv_malloc(sizeof(UCPTrie));
101
6
    if (trie == nullptr) {
102
0
        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
103
0
        return nullptr;
104
0
    }
105
6
    uprv_memcpy(trie, &tempTrie, sizeof(tempTrie));
106
#ifdef UCPTRIE_DEBUG
107
    trie->name = "fromSerialized";
108
#endif
109
110
    // Set the pointers to its index and data arrays.
111
6
    const uint16_t *p16 = (const uint16_t *)(header + 1);
112
6
    trie->index = p16;
113
6
    p16 += trie->indexLength;
114
115
    // Get the data.
116
6
    int32_t nullValueOffset = trie->dataNullOffset;
117
6
    if (nullValueOffset >= trie->dataLength) {
118
0
        nullValueOffset = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
119
0
    }
120
6
    switch (valueWidth) {
121
2
    case UCPTRIE_VALUE_BITS_16:
122
2
        trie->data.ptr16 = p16;
123
2
        trie->nullValue = trie->data.ptr16[nullValueOffset];
124
2
        break;
125
0
    case UCPTRIE_VALUE_BITS_32:
126
0
        trie->data.ptr32 = (const uint32_t *)p16;
127
0
        trie->nullValue = trie->data.ptr32[nullValueOffset];
128
0
        break;
129
4
    case UCPTRIE_VALUE_BITS_8:
130
4
        trie->data.ptr8 = (const uint8_t *)p16;
131
4
        trie->nullValue = trie->data.ptr8[nullValueOffset];
132
4
        break;
133
0
    default:
134
        // Unreachable because valueWidth was checked above.
135
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
136
0
        return nullptr;
137
6
    }
138
139
6
    if (pActualLength != nullptr) {
140
0
        *pActualLength = actualLength;
141
0
    }
142
6
    return trie;
143
6
}
144
145
U_CAPI void U_EXPORT2
146
0
ucptrie_close(UCPTrie *trie) {
147
0
    uprv_free(trie);
148
0
}
149
150
U_CAPI UCPTrieType U_EXPORT2
151
0
ucptrie_getType(const UCPTrie *trie) {
152
0
    return (UCPTrieType)trie->type;
153
0
}
154
155
U_CAPI UCPTrieValueWidth U_EXPORT2
156
0
ucptrie_getValueWidth(const UCPTrie *trie) {
157
0
    return (UCPTrieValueWidth)trie->valueWidth;
158
0
}
159
160
U_CAPI int32_t U_EXPORT2
161
26.7k
ucptrie_internalSmallIndex(const UCPTrie *trie, UChar32 c) {
162
26.7k
    int32_t i1 = c >> UCPTRIE_SHIFT_1;
163
26.7k
    if (trie->type == UCPTRIE_TYPE_FAST) {
164
22.7k
        U_ASSERT(0xffff < c && c < trie->highStart);
165
22.7k
        i1 += UCPTRIE_BMP_INDEX_LENGTH - UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH;
166
22.7k
    } else {
167
3.99k
        U_ASSERT((uint32_t)c < (uint32_t)trie->highStart && trie->highStart > UCPTRIE_SMALL_LIMIT);
168
3.99k
        i1 += UCPTRIE_SMALL_INDEX_LENGTH;
169
3.99k
    }
170
26.7k
    int32_t i3Block = trie->index[
171
26.7k
        (int32_t)trie->index[i1] + ((c >> UCPTRIE_SHIFT_2) & UCPTRIE_INDEX_2_MASK)];
172
26.7k
    int32_t i3 = (c >> UCPTRIE_SHIFT_3) & UCPTRIE_INDEX_3_MASK;
173
26.7k
    int32_t dataBlock;
174
26.7k
    if ((i3Block & 0x8000) == 0) {
175
        // 16-bit indexes
176
26.7k
        dataBlock = trie->index[i3Block + i3];
177
26.7k
    } else {
178
        // 18-bit indexes stored in groups of 9 entries per 8 indexes.
179
0
        i3Block = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3);
180
0
        i3 &= 7;
181
0
        dataBlock = ((int32_t)trie->index[i3Block++] << (2 + (2 * i3))) & 0x30000;
182
0
        dataBlock |= trie->index[i3Block + i3];
183
0
    }
184
26.7k
    return dataBlock + (c & UCPTRIE_SMALL_DATA_MASK);
185
26.7k
}
186
187
U_CAPI int32_t U_EXPORT2
188
0
ucptrie_internalSmallU8Index(const UCPTrie *trie, int32_t lt1, uint8_t t2, uint8_t t3) {
189
0
    UChar32 c = (lt1 << 12) | (t2 << 6) | t3;
190
0
    if (c >= trie->highStart) {
191
        // Possible because the UTF-8 macro compares with shifted12HighStart which may be higher.
192
0
        return trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
193
0
    }
194
0
    return ucptrie_internalSmallIndex(trie, c);
195
0
}
196
197
U_CAPI int32_t U_EXPORT2
198
ucptrie_internalU8PrevIndex(const UCPTrie *trie, UChar32 c,
199
0
                            const uint8_t *start, const uint8_t *src) {
200
0
    int32_t i, length;
201
    // Support 64-bit pointers by avoiding cast of arbitrary difference.
202
0
    if ((src - start) <= 7) {
203
0
        i = length = (int32_t)(src - start);
204
0
    } else {
205
0
        i = length = 7;
206
0
        start = src - 7;
207
0
    }
208
0
    c = utf8_prevCharSafeBody(start, 0, &i, c, -1);
209
0
    i = length - i;  // Number of bytes read backward from src.
210
0
    int32_t idx = _UCPTRIE_CP_INDEX(trie, 0xffff, c);
211
0
    return (idx << 3) | i;
212
0
}
213
214
namespace {
215
216
191k
inline uint32_t getValue(UCPTrieData data, UCPTrieValueWidth valueWidth, int32_t dataIndex) {
217
191k
    switch (valueWidth) {
218
150k
    case UCPTRIE_VALUE_BITS_16:
219
150k
        return data.ptr16[dataIndex];
220
18.4k
    case UCPTRIE_VALUE_BITS_32:
221
18.4k
        return data.ptr32[dataIndex];
222
23.1k
    case UCPTRIE_VALUE_BITS_8:
223
23.1k
        return data.ptr8[dataIndex];
224
0
    default:
225
        // Unreachable if the trie is properly initialized.
226
0
        return 0xffffffff;
227
191k
    }
228
191k
}
229
230
}  // namespace
231
232
U_CAPI uint32_t U_EXPORT2
233
5.93k
ucptrie_get(const UCPTrie *trie, UChar32 c) {
234
5.93k
    int32_t dataIndex;
235
5.93k
    if ((uint32_t)c <= 0x7f) {
236
        // linear ASCII
237
61
        dataIndex = c;
238
5.87k
    } else {
239
5.87k
        UChar32 fastMax = trie->type == UCPTRIE_TYPE_FAST ? 0xffff : UCPTRIE_SMALL_MAX;
240
5.87k
        dataIndex = _UCPTRIE_CP_INDEX(trie, fastMax, c);
241
5.87k
    }
242
5.93k
    return getValue(trie->data, (UCPTrieValueWidth)trie->valueWidth, dataIndex);
243
5.93k
}
244
245
namespace {
246
247
constexpr int32_t MAX_UNICODE = 0x10ffff;
248
249
inline uint32_t maybeFilterValue(uint32_t value, uint32_t trieNullValue, uint32_t nullValue,
250
34.4k
                                 UCPMapValueFilter *filter, const void *context) {
251
34.4k
    if (value == trieNullValue) {
252
5.03k
        value = nullValue;
253
29.4k
    } else if (filter != nullptr) {
254
1.61k
        value = filter(context, value);
255
1.61k
    }
256
34.4k
    return value;
257
34.4k
}
258
259
UChar32 getRange(const void *t, UChar32 start,
260
31.9k
                 UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
261
31.9k
    if (static_cast<uint32_t>(start) > MAX_UNICODE) {
262
10
        return U_SENTINEL;
263
10
    }
264
31.9k
    const UCPTrie *trie = reinterpret_cast<const UCPTrie *>(t);
265
31.9k
    UCPTrieValueWidth valueWidth = static_cast<UCPTrieValueWidth>(trie->valueWidth);
266
31.9k
    if (start >= trie->highStart) {
267
1
        if (pValue != nullptr) {
268
1
            int32_t di = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
269
1
            uint32_t value = getValue(trie->data, valueWidth, di);
270
1
            if (filter != nullptr) { value = filter(context, value); }
271
1
            *pValue = value;
272
1
        }
273
1
        return MAX_UNICODE;
274
1
    }
275
276
31.9k
    uint32_t nullValue = trie->nullValue;
277
31.9k
    if (filter != nullptr) { nullValue = filter(context, nullValue); }
278
31.9k
    const uint16_t *index = trie->index;
279
280
31.9k
    int32_t prevI3Block = -1;
281
31.9k
    int32_t prevBlock = -1;
282
31.9k
    UChar32 c = start;
283
31.9k
    uint32_t trieValue, value = nullValue;
284
31.9k
    bool haveValue = false;
285
39.2k
    do {
286
39.2k
        int32_t i3Block;
287
39.2k
        int32_t i3;
288
39.2k
        int32_t i3BlockLength;
289
39.2k
        int32_t dataBlockLength;
290
39.2k
        if (c <= 0xffff && (trie->type == UCPTRIE_TYPE_FAST || c <= UCPTRIE_SMALL_MAX)) {
291
22.4k
            i3Block = 0;
292
22.4k
            i3 = c >> UCPTRIE_FAST_SHIFT;
293
22.4k
            i3BlockLength = trie->type == UCPTRIE_TYPE_FAST ?
294
21.4k
                UCPTRIE_BMP_INDEX_LENGTH : UCPTRIE_SMALL_INDEX_LENGTH;
295
22.4k
            dataBlockLength = UCPTRIE_FAST_DATA_BLOCK_LENGTH;
296
22.4k
        } else {
297
            // Use the multi-stage index.
298
16.8k
            int32_t i1 = c >> UCPTRIE_SHIFT_1;
299
16.8k
            if (trie->type == UCPTRIE_TYPE_FAST) {
300
11.7k
                U_ASSERT(0xffff < c && c < trie->highStart);
301
11.7k
                i1 += UCPTRIE_BMP_INDEX_LENGTH - UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH;
302
11.7k
            } else {
303
5.10k
                U_ASSERT(c < trie->highStart && trie->highStart > UCPTRIE_SMALL_LIMIT);
304
5.10k
                i1 += UCPTRIE_SMALL_INDEX_LENGTH;
305
5.10k
            }
306
16.8k
            i3Block = trie->index[
307
16.8k
                static_cast<int32_t>(trie->index[i1]) + ((c >> UCPTRIE_SHIFT_2) & UCPTRIE_INDEX_2_MASK)];
308
16.8k
            if (i3Block == prevI3Block && (c - start) >= UCPTRIE_CP_PER_INDEX_2_ENTRY) {
309
                // The index-3 block is the same as the previous one, and filled with value.
310
6.79k
                U_ASSERT((c & (UCPTRIE_CP_PER_INDEX_2_ENTRY - 1)) == 0);
311
6.79k
                c += UCPTRIE_CP_PER_INDEX_2_ENTRY;
312
6.79k
                continue;
313
6.79k
            }
314
10.0k
            prevI3Block = i3Block;
315
10.0k
            if (i3Block == trie->index3NullOffset) {
316
                // This is the index-3 null block.
317
124
                if (haveValue) {
318
117
                    if (nullValue != value) {
319
7
                        return c - 1;
320
7
                    }
321
117
                } else {
322
7
                    trieValue = trie->nullValue;
323
7
                    value = nullValue;
324
7
                    if (pValue != nullptr) { *pValue = nullValue; }
325
7
                    haveValue = true;
326
7
                }
327
117
                prevBlock = trie->dataNullOffset;
328
117
                c = (c + UCPTRIE_CP_PER_INDEX_2_ENTRY) & ~(UCPTRIE_CP_PER_INDEX_2_ENTRY - 1);
329
117
                continue;
330
124
            }
331
9.90k
            i3 = (c >> UCPTRIE_SHIFT_3) & UCPTRIE_INDEX_3_MASK;
332
9.90k
            i3BlockLength = UCPTRIE_INDEX_3_BLOCK_LENGTH;
333
9.90k
            dataBlockLength = UCPTRIE_SMALL_DATA_BLOCK_LENGTH;
334
9.90k
        }
335
        // Enumerate data blocks for one index-3 block.
336
51.7k
        do {
337
51.7k
            int32_t block;
338
51.7k
            if ((i3Block & 0x8000) == 0) {
339
51.7k
                block = index[i3Block + i3];
340
51.7k
            } else {
341
                // 18-bit indexes stored in groups of 9 entries per 8 indexes.
342
0
                int32_t group = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3);
343
0
                int32_t gi = i3 & 7;
344
0
                block = (static_cast<int32_t>(index[group++]) << (2 + (2 * gi))) & 0x30000;
345
0
                block |= index[group + gi];
346
0
            }
347
51.7k
            if (block == prevBlock && (c - start) >= dataBlockLength) {
348
                // The block is the same as the previous one, and filled with value.
349
14.4k
                U_ASSERT((c & (dataBlockLength - 1)) == 0);
350
14.4k
                c += dataBlockLength;
351
37.3k
            } else {
352
37.3k
                int32_t dataMask = dataBlockLength - 1;
353
37.3k
                prevBlock = block;
354
37.3k
                if (block == trie->dataNullOffset) {
355
                    // This is the data null block.
356
1.33k
                    if (haveValue) {
357
1.19k
                        if (nullValue != value) {
358
133
                            return c - 1;
359
133
                        }
360
1.19k
                    } else {
361
140
                        trieValue = trie->nullValue;
362
140
                        value = nullValue;
363
140
                        if (pValue != nullptr) { *pValue = nullValue; }
364
140
                        haveValue = true;
365
140
                    }
366
1.20k
                    c = (c + dataBlockLength) & ~dataMask;
367
36.0k
                } else {
368
36.0k
                    int32_t di = block + (c & dataMask);
369
36.0k
                    uint32_t trieValue2 = getValue(trie->data, valueWidth, di);
370
36.0k
                    if (haveValue) {
371
4.22k
                        if (trieValue2 != trieValue) {
372
1.41k
                            if (filter == nullptr ||
373
1.41k
                                    maybeFilterValue(trieValue2, trie->nullValue, nullValue,
374
1.31k
                                                     filter, context) != value) {
375
1.31k
                                return c - 1;
376
1.31k
                            }
377
108
                            trieValue = trieValue2;  // may or may not help
378
108
                        }
379
31.8k
                    } else {
380
31.8k
                        trieValue = trieValue2;
381
31.8k
                        value = maybeFilterValue(trieValue2, trie->nullValue, nullValue,
382
31.8k
                                                 filter, context);
383
31.8k
                        if (pValue != nullptr) { *pValue = value; }
384
31.8k
                        haveValue = true;
385
31.8k
                    }
386
153k
                    while ((++c & dataMask) != 0) {
387
149k
                        trieValue2 = getValue(trie->data, valueWidth, ++di);
388
149k
                        if (trieValue2 != trieValue) {
389
32.6k
                            if (filter == nullptr ||
390
32.6k
                                    maybeFilterValue(trieValue2, trie->nullValue, nullValue,
391
30.4k
                                                     filter, context) != value) {
392
30.4k
                                return c - 1;
393
30.4k
                            }
394
2.11k
                            trieValue = trieValue2;  // may or may not help
395
2.11k
                        }
396
149k
                    }
397
34.7k
                }
398
37.3k
            }
399
51.7k
        } while (++i3 < i3BlockLength);
400
32.3k
    } while (c < trie->highStart);
401
11
    U_ASSERT(haveValue);
402
11
    int32_t di = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
403
11
    uint32_t highValue = getValue(trie->data, valueWidth, di);
404
11
    if (maybeFilterValue(highValue, trie->nullValue, nullValue,
405
11
                         filter, context) != value) {
406
2
        return c - 1;
407
9
    } else {
408
9
        return MAX_UNICODE;
409
9
    }
410
11
}
411
412
}  // namespace
413
414
U_CFUNC UChar32
415
ucptrie_internalGetRange(UCPTrieGetRange *getRange,
416
                         const void *trie, UChar32 start,
417
                         UCPMapRangeOption option, uint32_t surrogateValue,
418
31.9k
                         UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
419
31.9k
    if (option == UCPMAP_RANGE_NORMAL) {
420
3.60k
        return getRange(trie, start, filter, context, pValue);
421
3.60k
    }
422
28.3k
    uint32_t value;
423
28.3k
    if (pValue == nullptr) {
424
        // We need to examine the range value even if the caller does not want it.
425
0
        pValue = &value;
426
0
    }
427
28.3k
    UChar32 surrEnd = option == UCPMAP_RANGE_FIXED_ALL_SURROGATES ? 0xdfff : 0xdbff;
428
28.3k
    UChar32 end = getRange(trie, start, filter, context, pValue);
429
28.3k
    if (end < 0xd7ff || start > surrEnd) {
430
28.3k
        return end;
431
28.3k
    }
432
    // The range overlaps with surrogates, or ends just before the first one.
433
5
    if (*pValue == surrogateValue) {
434
5
        if (end >= surrEnd) {
435
            // Surrogates followed by a non-surrogateValue range,
436
            // or surrogates are part of a larger surrogateValue range.
437
0
            return end;
438
0
        }
439
5
    } else {
440
0
        if (start <= 0xd7ff) {
441
0
            return 0xd7ff;  // Non-surrogateValue range ends before surrogateValue surrogates.
442
0
        }
443
        // Start is a surrogate with a non-surrogateValue code *unit* value.
444
        // Return a surrogateValue code *point* range.
445
0
        *pValue = surrogateValue;
446
0
        if (end > surrEnd) {
447
0
            return surrEnd;  // Surrogate range ends before non-surrogateValue rest of range.
448
0
        }
449
0
    }
450
    // See if the surrogateValue surrogate range can be merged with
451
    // an immediately following range.
452
5
    uint32_t value2;
453
5
    UChar32 end2 = getRange(trie, surrEnd + 1, filter, context, &value2);
454
5
    if (value2 == surrogateValue) {
455
5
        return end2;
456
5
    }
457
0
    return surrEnd;
458
5
}
459
460
U_CAPI UChar32 U_EXPORT2
461
ucptrie_getRange(const UCPTrie *trie, UChar32 start,
462
                 UCPMapRangeOption option, uint32_t surrogateValue,
463
31.9k
                 UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
464
31.9k
    return ucptrie_internalGetRange(getRange, trie, start,
465
31.9k
                                    option, surrogateValue,
466
31.9k
                                    filter, context, pValue);
467
31.9k
}
468
469
U_CAPI int32_t U_EXPORT2
470
ucptrie_toBinary(const UCPTrie *trie,
471
                 void *data, int32_t capacity,
472
0
                 UErrorCode *pErrorCode) {
473
0
    if (U_FAILURE(*pErrorCode)) {
474
0
        return 0;
475
0
    }
476
477
0
    UCPTrieType type = (UCPTrieType)trie->type;
478
0
    UCPTrieValueWidth valueWidth = (UCPTrieValueWidth)trie->valueWidth;
479
0
    if (type < UCPTRIE_TYPE_FAST || UCPTRIE_TYPE_SMALL < type ||
480
0
            valueWidth < UCPTRIE_VALUE_BITS_16 || UCPTRIE_VALUE_BITS_8 < valueWidth ||
481
0
            capacity < 0 ||
482
0
            (capacity > 0 && (data == nullptr || (U_POINTER_MASK_LSB(data, 3) != 0)))) {
483
0
        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
484
0
        return 0;
485
0
    }
486
487
0
    int32_t length = (int32_t)sizeof(UCPTrieHeader) + trie->indexLength * 2;
488
0
    switch (valueWidth) {
489
0
    case UCPTRIE_VALUE_BITS_16:
490
0
        length += trie->dataLength * 2;
491
0
        break;
492
0
    case UCPTRIE_VALUE_BITS_32:
493
0
        length += trie->dataLength * 4;
494
0
        break;
495
0
    case UCPTRIE_VALUE_BITS_8:
496
0
        length += trie->dataLength;
497
0
        break;
498
0
    default:
499
        // unreachable
500
0
        break;
501
0
    }
502
0
    if (capacity < length) {
503
0
        *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
504
0
        return length;
505
0
    }
506
507
0
    char *bytes = (char *)data;
508
0
    UCPTrieHeader *header = (UCPTrieHeader *)bytes;
509
0
    header->signature = UCPTRIE_SIG;  // "Tri3"
510
0
    header->options = (uint16_t)(
511
0
        ((trie->dataLength & 0xf0000) >> 4) |
512
0
        ((trie->dataNullOffset & 0xf0000) >> 8) |
513
0
        (trie->type << 6) |
514
0
        valueWidth);
515
0
    header->indexLength = (uint16_t)trie->indexLength;
516
0
    header->dataLength = (uint16_t)trie->dataLength;
517
0
    header->index3NullOffset = trie->index3NullOffset;
518
0
    header->dataNullOffset = (uint16_t)trie->dataNullOffset;
519
0
    header->shiftedHighStart = trie->highStart >> UCPTRIE_SHIFT_2;
520
0
    bytes += sizeof(UCPTrieHeader);
521
522
0
    uprv_memcpy(bytes, trie->index, trie->indexLength * 2);
523
0
    bytes += trie->indexLength * 2;
524
525
0
    switch (valueWidth) {
526
0
    case UCPTRIE_VALUE_BITS_16:
527
0
        uprv_memcpy(bytes, trie->data.ptr16, trie->dataLength * 2);
528
0
        break;
529
0
    case UCPTRIE_VALUE_BITS_32:
530
0
        uprv_memcpy(bytes, trie->data.ptr32, trie->dataLength * 4);
531
0
        break;
532
0
    case UCPTRIE_VALUE_BITS_8:
533
0
        uprv_memcpy(bytes, trie->data.ptr8, trie->dataLength);
534
0
        break;
535
0
    default:
536
        // unreachable
537
0
        break;
538
0
    }
539
0
    return length;
540
0
}
541
542
namespace {
543
544
#ifdef UCPTRIE_DEBUG
545
long countNull(const UCPTrie *trie) {
546
    uint32_t nullValue=trie->nullValue;
547
    int32_t length=trie->dataLength;
548
    long count=0;
549
    switch (trie->valueWidth) {
550
    case UCPTRIE_VALUE_BITS_16:
551
        for(int32_t i=0; i<length; ++i) {
552
            if(trie->data.ptr16[i]==nullValue) { ++count; }
553
        }
554
        break;
555
    case UCPTRIE_VALUE_BITS_32:
556
        for(int32_t i=0; i<length; ++i) {
557
            if(trie->data.ptr32[i]==nullValue) { ++count; }
558
        }
559
        break;
560
    case UCPTRIE_VALUE_BITS_8:
561
        for(int32_t i=0; i<length; ++i) {
562
            if(trie->data.ptr8[i]==nullValue) { ++count; }
563
        }
564
        break;
565
    default:
566
        // unreachable
567
        break;
568
    }
569
    return count;
570
}
571
572
U_CFUNC void
573
ucptrie_printLengths(const UCPTrie *trie, const char *which) {
574
    long indexLength=trie->indexLength;
575
    long dataLength=(long)trie->dataLength;
576
    long totalLength=(long)sizeof(UCPTrieHeader)+indexLength*2+
577
            dataLength*(trie->valueWidth==UCPTRIE_VALUE_BITS_16 ? 2 :
578
                        trie->valueWidth==UCPTRIE_VALUE_BITS_32 ? 4 : 1);
579
    printf("**UCPTrieLengths(%s %s)** index:%6ld  data:%6ld  countNull:%6ld  serialized:%6ld\n",
580
           which, trie->name, indexLength, dataLength, countNull(trie), totalLength);
581
}
582
#endif
583
584
}  // namespace
585
586
// UCPMap ----
587
// Initially, this is the same as UCPTrie. This may well change.
588
589
U_CAPI uint32_t U_EXPORT2
590
0
ucpmap_get(const UCPMap *map, UChar32 c) {
591
0
    return ucptrie_get(reinterpret_cast<const UCPTrie *>(map), c);
592
0
}
593
594
U_CAPI UChar32 U_EXPORT2
595
ucpmap_getRange(const UCPMap *map, UChar32 start,
596
                UCPMapRangeOption option, uint32_t surrogateValue,
597
0
                UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
598
0
    return ucptrie_getRange(reinterpret_cast<const UCPTrie *>(map), start,
599
0
                            option, surrogateValue,
600
0
                            filter, context, pValue);
601
0
}