Coverage Report

Created: 2025-06-24 06:43

/src/icu/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
0
                       UErrorCode *pErrorCode) {
25
0
    if (U_FAILURE(*pErrorCode)) {
26
0
        return nullptr;
27
0
    }
28
29
0
    if (length <= 0 || (U_POINTER_MASK_LSB(data, 3) != 0) ||
30
0
            type < UCPTRIE_TYPE_ANY || UCPTRIE_TYPE_SMALL < type ||
31
0
            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
0
    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
0
    const UCPTrieHeader *header = (const UCPTrieHeader *)data;
44
0
    if (header->signature != UCPTRIE_SIG) {
45
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
46
0
        return nullptr;
47
0
    }
48
49
0
    int32_t options = header->options;
50
0
    int32_t typeInt = (options >> 6) & 3;
51
0
    int32_t valueWidthInt = options & UCPTRIE_OPTIONS_VALUE_BITS_MASK;
52
0
    if (typeInt > UCPTRIE_TYPE_SMALL || valueWidthInt > UCPTRIE_VALUE_BITS_8 ||
53
0
            (options & UCPTRIE_OPTIONS_RESERVED_MASK) != 0) {
54
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
55
0
        return nullptr;
56
0
    }
57
0
    UCPTrieType actualType = (UCPTrieType)typeInt;
58
0
    UCPTrieValueWidth actualValueWidth = (UCPTrieValueWidth)valueWidthInt;
59
0
    if (type < 0) {
60
0
        type = actualType;
61
0
    }
62
0
    if (valueWidth < 0) {
63
0
        valueWidth = actualValueWidth;
64
0
    }
65
0
    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
0
    UCPTrie tempTrie;
72
0
    uprv_memset(&tempTrie, 0, sizeof(tempTrie));
73
0
    tempTrie.indexLength = header->indexLength;
74
0
    tempTrie.dataLength =
75
0
        ((options & UCPTRIE_OPTIONS_DATA_LENGTH_MASK) << 4) | header->dataLength;
76
0
    tempTrie.index3NullOffset = header->index3NullOffset;
77
0
    tempTrie.dataNullOffset =
78
0
        ((options & UCPTRIE_OPTIONS_DATA_NULL_OFFSET_MASK) << 8) | header->dataNullOffset;
79
80
0
    tempTrie.highStart = header->shiftedHighStart << UCPTRIE_SHIFT_2;
81
0
    tempTrie.shifted12HighStart = (tempTrie.highStart + 0xfff) >> 12;
82
0
    tempTrie.type = type;
83
0
    tempTrie.valueWidth = valueWidth;
84
85
    // Calculate the actual length.
86
0
    int32_t actualLength = (int32_t)sizeof(UCPTrieHeader) + tempTrie.indexLength * 2;
87
0
    if (valueWidth == UCPTRIE_VALUE_BITS_16) {
88
0
        actualLength += tempTrie.dataLength * 2;
89
0
    } else if (valueWidth == UCPTRIE_VALUE_BITS_32) {
90
0
        actualLength += tempTrie.dataLength * 4;
91
0
    } else {
92
0
        actualLength += tempTrie.dataLength;
93
0
    }
94
0
    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
0
    UCPTrie *trie = (UCPTrie *)uprv_malloc(sizeof(UCPTrie));
101
0
    if (trie == nullptr) {
102
0
        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
103
0
        return nullptr;
104
0
    }
105
0
    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
0
    const uint16_t *p16 = (const uint16_t *)(header + 1);
112
0
    trie->index = p16;
113
0
    p16 += trie->indexLength;
114
115
    // Get the data.
116
0
    int32_t nullValueOffset = trie->dataNullOffset;
117
0
    if (nullValueOffset >= trie->dataLength) {
118
0
        nullValueOffset = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
119
0
    }
120
0
    switch (valueWidth) {
121
0
    case UCPTRIE_VALUE_BITS_16:
122
0
        trie->data.ptr16 = p16;
123
0
        trie->nullValue = trie->data.ptr16[nullValueOffset];
124
0
        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
0
    case UCPTRIE_VALUE_BITS_8:
130
0
        trie->data.ptr8 = (const uint8_t *)p16;
131
0
        trie->nullValue = trie->data.ptr8[nullValueOffset];
132
0
        break;
133
0
    default:
134
        // Unreachable because valueWidth was checked above.
135
0
        *pErrorCode = U_INVALID_FORMAT_ERROR;
136
0
        return nullptr;
137
0
    }
138
139
0
    if (pActualLength != nullptr) {
140
0
        *pActualLength = actualLength;
141
0
    }
142
0
    return trie;
143
0
}
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
0
ucptrie_internalSmallIndex(const UCPTrie *trie, UChar32 c) {
162
0
    int32_t i1 = c >> UCPTRIE_SHIFT_1;
163
0
    if (trie->type == UCPTRIE_TYPE_FAST) {
164
0
        U_ASSERT(0xffff < c && c < trie->highStart);
165
0
        i1 += UCPTRIE_BMP_INDEX_LENGTH - UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH;
166
0
    } else {
167
0
        U_ASSERT((uint32_t)c < (uint32_t)trie->highStart && trie->highStart > UCPTRIE_SMALL_LIMIT);
168
0
        i1 += UCPTRIE_SMALL_INDEX_LENGTH;
169
0
    }
170
0
    int32_t i3Block = trie->index[
171
0
        (int32_t)trie->index[i1] + ((c >> UCPTRIE_SHIFT_2) & UCPTRIE_INDEX_2_MASK)];
172
0
    int32_t i3 = (c >> UCPTRIE_SHIFT_3) & UCPTRIE_INDEX_3_MASK;
173
0
    int32_t dataBlock;
174
0
    if ((i3Block & 0x8000) == 0) {
175
        // 16-bit indexes
176
0
        dataBlock = trie->index[i3Block + i3];
177
0
    } 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
0
    return dataBlock + (c & UCPTRIE_SMALL_DATA_MASK);
185
0
}
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
0
inline uint32_t getValue(UCPTrieData data, UCPTrieValueWidth valueWidth, int32_t dataIndex) {
217
0
    switch (valueWidth) {
218
0
    case UCPTRIE_VALUE_BITS_16:
219
0
        return data.ptr16[dataIndex];
220
0
    case UCPTRIE_VALUE_BITS_32:
221
0
        return data.ptr32[dataIndex];
222
0
    case UCPTRIE_VALUE_BITS_8:
223
0
        return data.ptr8[dataIndex];
224
0
    default:
225
        // Unreachable if the trie is properly initialized.
226
0
        return 0xffffffff;
227
0
    }
228
0
}
229
230
}  // namespace
231
232
U_CAPI uint32_t U_EXPORT2
233
0
ucptrie_get(const UCPTrie *trie, UChar32 c) {
234
0
    int32_t dataIndex;
235
0
    if ((uint32_t)c <= 0x7f) {
236
        // linear ASCII
237
0
        dataIndex = c;
238
0
    } else {
239
0
        UChar32 fastMax = trie->type == UCPTRIE_TYPE_FAST ? 0xffff : UCPTRIE_SMALL_MAX;
240
0
        dataIndex = _UCPTRIE_CP_INDEX(trie, fastMax, c);
241
0
    }
242
0
    return getValue(trie->data, (UCPTrieValueWidth)trie->valueWidth, dataIndex);
243
0
}
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
0
                                 UCPMapValueFilter *filter, const void *context) {
251
0
    if (value == trieNullValue) {
252
0
        value = nullValue;
253
0
    } else if (filter != nullptr) {
254
0
        value = filter(context, value);
255
0
    }
256
0
    return value;
257
0
}
258
259
UChar32 getRange(const void *t, UChar32 start,
260
0
                 UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
261
0
    if ((uint32_t)start > MAX_UNICODE) {
262
0
        return U_SENTINEL;
263
0
    }
264
0
    const UCPTrie *trie = reinterpret_cast<const UCPTrie *>(t);
265
0
    UCPTrieValueWidth valueWidth = (UCPTrieValueWidth)trie->valueWidth;
266
0
    if (start >= trie->highStart) {
267
0
        if (pValue != nullptr) {
268
0
            int32_t di = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
269
0
            uint32_t value = getValue(trie->data, valueWidth, di);
270
0
            if (filter != nullptr) { value = filter(context, value); }
271
0
            *pValue = value;
272
0
        }
273
0
        return MAX_UNICODE;
274
0
    }
275
276
0
    uint32_t nullValue = trie->nullValue;
277
0
    if (filter != nullptr) { nullValue = filter(context, nullValue); }
278
0
    const uint16_t *index = trie->index;
279
280
0
    int32_t prevI3Block = -1;
281
0
    int32_t prevBlock = -1;
282
0
    UChar32 c = start;
283
0
    uint32_t trieValue, value = nullValue;
284
0
    bool haveValue = false;
285
0
    do {
286
0
        int32_t i3Block;
287
0
        int32_t i3;
288
0
        int32_t i3BlockLength;
289
0
        int32_t dataBlockLength;
290
0
        if (c <= 0xffff && (trie->type == UCPTRIE_TYPE_FAST || c <= UCPTRIE_SMALL_MAX)) {
291
0
            i3Block = 0;
292
0
            i3 = c >> UCPTRIE_FAST_SHIFT;
293
0
            i3BlockLength = trie->type == UCPTRIE_TYPE_FAST ?
294
0
                UCPTRIE_BMP_INDEX_LENGTH : UCPTRIE_SMALL_INDEX_LENGTH;
295
0
            dataBlockLength = UCPTRIE_FAST_DATA_BLOCK_LENGTH;
296
0
        } else {
297
            // Use the multi-stage index.
298
0
            int32_t i1 = c >> UCPTRIE_SHIFT_1;
299
0
            if (trie->type == UCPTRIE_TYPE_FAST) {
300
0
                U_ASSERT(0xffff < c && c < trie->highStart);
301
0
                i1 += UCPTRIE_BMP_INDEX_LENGTH - UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH;
302
0
            } else {
303
0
                U_ASSERT(c < trie->highStart && trie->highStart > UCPTRIE_SMALL_LIMIT);
304
0
                i1 += UCPTRIE_SMALL_INDEX_LENGTH;
305
0
            }
306
0
            i3Block = trie->index[
307
0
                (int32_t)trie->index[i1] + ((c >> UCPTRIE_SHIFT_2) & UCPTRIE_INDEX_2_MASK)];
308
0
            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
0
                U_ASSERT((c & (UCPTRIE_CP_PER_INDEX_2_ENTRY - 1)) == 0);
311
0
                c += UCPTRIE_CP_PER_INDEX_2_ENTRY;
312
0
                continue;
313
0
            }
314
0
            prevI3Block = i3Block;
315
0
            if (i3Block == trie->index3NullOffset) {
316
                // This is the index-3 null block.
317
0
                if (haveValue) {
318
0
                    if (nullValue != value) {
319
0
                        return c - 1;
320
0
                    }
321
0
                } else {
322
0
                    trieValue = trie->nullValue;
323
0
                    value = nullValue;
324
0
                    if (pValue != nullptr) { *pValue = nullValue; }
325
0
                    haveValue = true;
326
0
                }
327
0
                prevBlock = trie->dataNullOffset;
328
0
                c = (c + UCPTRIE_CP_PER_INDEX_2_ENTRY) & ~(UCPTRIE_CP_PER_INDEX_2_ENTRY - 1);
329
0
                continue;
330
0
            }
331
0
            i3 = (c >> UCPTRIE_SHIFT_3) & UCPTRIE_INDEX_3_MASK;
332
0
            i3BlockLength = UCPTRIE_INDEX_3_BLOCK_LENGTH;
333
0
            dataBlockLength = UCPTRIE_SMALL_DATA_BLOCK_LENGTH;
334
0
        }
335
        // Enumerate data blocks for one index-3 block.
336
0
        do {
337
0
            int32_t block;
338
0
            if ((i3Block & 0x8000) == 0) {
339
0
                block = index[i3Block + i3];
340
0
            } 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 = ((int32_t)index[group++] << (2 + (2 * gi))) & 0x30000;
345
0
                block |= index[group + gi];
346
0
            }
347
0
            if (block == prevBlock && (c - start) >= dataBlockLength) {
348
                // The block is the same as the previous one, and filled with value.
349
0
                U_ASSERT((c & (dataBlockLength - 1)) == 0);
350
0
                c += dataBlockLength;
351
0
            } else {
352
0
                int32_t dataMask = dataBlockLength - 1;
353
0
                prevBlock = block;
354
0
                if (block == trie->dataNullOffset) {
355
                    // This is the data null block.
356
0
                    if (haveValue) {
357
0
                        if (nullValue != value) {
358
0
                            return c - 1;
359
0
                        }
360
0
                    } else {
361
0
                        trieValue = trie->nullValue;
362
0
                        value = nullValue;
363
0
                        if (pValue != nullptr) { *pValue = nullValue; }
364
0
                        haveValue = true;
365
0
                    }
366
0
                    c = (c + dataBlockLength) & ~dataMask;
367
0
                } else {
368
0
                    int32_t di = block + (c & dataMask);
369
0
                    uint32_t trieValue2 = getValue(trie->data, valueWidth, di);
370
0
                    if (haveValue) {
371
0
                        if (trieValue2 != trieValue) {
372
0
                            if (filter == nullptr ||
373
0
                                    maybeFilterValue(trieValue2, trie->nullValue, nullValue,
374
0
                                                     filter, context) != value) {
375
0
                                return c - 1;
376
0
                            }
377
0
                            trieValue = trieValue2;  // may or may not help
378
0
                        }
379
0
                    } else {
380
0
                        trieValue = trieValue2;
381
0
                        value = maybeFilterValue(trieValue2, trie->nullValue, nullValue,
382
0
                                                 filter, context);
383
0
                        if (pValue != nullptr) { *pValue = value; }
384
0
                        haveValue = true;
385
0
                    }
386
0
                    while ((++c & dataMask) != 0) {
387
0
                        trieValue2 = getValue(trie->data, valueWidth, ++di);
388
0
                        if (trieValue2 != trieValue) {
389
0
                            if (filter == nullptr ||
390
0
                                    maybeFilterValue(trieValue2, trie->nullValue, nullValue,
391
0
                                                     filter, context) != value) {
392
0
                                return c - 1;
393
0
                            }
394
0
                            trieValue = trieValue2;  // may or may not help
395
0
                        }
396
0
                    }
397
0
                }
398
0
            }
399
0
        } while (++i3 < i3BlockLength);
400
0
    } while (c < trie->highStart);
401
0
    U_ASSERT(haveValue);
402
0
    int32_t di = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
403
0
    uint32_t highValue = getValue(trie->data, valueWidth, di);
404
0
    if (maybeFilterValue(highValue, trie->nullValue, nullValue,
405
0
                         filter, context) != value) {
406
0
        return c - 1;
407
0
    } else {
408
0
        return MAX_UNICODE;
409
0
    }
410
0
}
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
0
                         UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
419
0
    if (option == UCPMAP_RANGE_NORMAL) {
420
0
        return getRange(trie, start, filter, context, pValue);
421
0
    }
422
0
    uint32_t value;
423
0
    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
0
    UChar32 surrEnd = option == UCPMAP_RANGE_FIXED_ALL_SURROGATES ? 0xdfff : 0xdbff;
428
0
    UChar32 end = getRange(trie, start, filter, context, pValue);
429
0
    if (end < 0xd7ff || start > surrEnd) {
430
0
        return end;
431
0
    }
432
    // The range overlaps with surrogates, or ends just before the first one.
433
0
    if (*pValue == surrogateValue) {
434
0
        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
0
    } 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
0
    uint32_t value2;
453
0
    UChar32 end2 = getRange(trie, surrEnd + 1, filter, context, &value2);
454
0
    if (value2 == surrogateValue) {
455
0
        return end2;
456
0
    }
457
0
    return surrEnd;
458
0
}
459
460
U_CAPI UChar32 U_EXPORT2
461
ucptrie_getRange(const UCPTrie *trie, UChar32 start,
462
                 UCPMapRangeOption option, uint32_t surrogateValue,
463
0
                 UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
464
0
    return ucptrie_internalGetRange(getRange, trie, start,
465
0
                                    option, surrogateValue,
466
0
                                    filter, context, pValue);
467
0
}
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
}