Coverage Report

Created: 2025-10-12 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/source/common/punycode.cpp
Line
Count
Source
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
*******************************************************************************
5
*
6
*   Copyright (C) 2002-2011, International Business Machines
7
*   Corporation and others.  All Rights Reserved.
8
*
9
*******************************************************************************
10
*   file name:  punycode.cpp
11
*   encoding:   UTF-8
12
*   tab size:   8 (not used)
13
*   indentation:4
14
*
15
*   created on: 2002jan31
16
*   created by: Markus W. Scherer
17
*/
18
19
20
/* This ICU code derived from: */
21
/*
22
punycode.c 0.4.0 (2001-Nov-17-Sat)
23
http://www.cs.berkeley.edu/~amc/idn/
24
Adam M. Costello
25
http://www.nicemice.net/amc/
26
27
Disclaimer and license
28
29
    Regarding this entire document or any portion of it (including
30
    the pseudocode and C code), the author makes no guarantees and
31
    is not responsible for any damage resulting from its use.  The
32
    author grants irrevocable permission to anyone to use, modify,
33
    and distribute it in any way that does not diminish the rights
34
    of anyone else to use, modify, and distribute it, provided that
35
    redistributed derivative works do not contain misleading author or
36
    version information.  Derivative works need not be licensed under
37
    similar terms.
38
*/
39
/*
40
 * ICU modifications:
41
 * - ICU data types and coding conventions
42
 * - ICU string buffer handling with implicit source lengths
43
 *   and destination preflighting
44
 * - UTF-16 handling
45
 */
46
47
#include "unicode/utypes.h"
48
49
#if !UCONFIG_NO_IDNA
50
51
#include "unicode/ustring.h"
52
#include "unicode/utf.h"
53
#include "unicode/utf16.h"
54
#include "ustr_imp.h"
55
#include "cstring.h"
56
#include "cmemory.h"
57
#include "punycode.h"
58
#include "uassert.h"
59
60
61
/* Punycode ----------------------------------------------------------------- */
62
63
/* Punycode parameters for Bootstring */
64
43.7M
#define BASE            36
65
33.9M
#define TMIN            1
66
14.9M
#define TMAX            26
67
4.88M
#define SKEW            38
68
4.72M
#define DAMP            700
69
4.72M
#define INITIAL_BIAS    72
70
4.72M
#define INITIAL_N       0x80
71
72
/* "Basic" Unicode/ASCII code points */
73
168k
#define _HYPHEN         0X2d
74
168k
#define DELIMITER       _HYPHEN
75
76
4.27M
#define _ZERO_          0X30
77
#define _NINE           0x39
78
79
10.1M
#define _SMALL_A        0X61
80
0
#define _SMALL_Z        0X7a
81
82
0
#define _CAPITAL_A      0X41
83
0
#define _CAPITAL_Z      0X5a
84
85
4.98M
#define IS_BASIC(c) ((c)<0x80)
86
0
#define IS_BASIC_UPPERCASE(c) (_CAPITAL_A<=(c) && (c)<=_CAPITAL_Z)
87
88
/**
89
 * digitToBasic() returns the basic code point whose value
90
 * (when used for representing integers) is d, which must be in the
91
 * range 0 to BASE-1. The lowercase form is used unless the uppercase flag is
92
 * nonzero, in which case the uppercase form is used.
93
 */
94
static inline char
95
14.4M
digitToBasic(int32_t digit, UBool uppercase) {
96
    /*  0..25 map to ASCII a..z or A..Z */
97
    /* 26..35 map to ASCII 0..9         */
98
14.4M
    if(digit<26) {
99
10.1M
        if(uppercase) {
100
0
            return (char)(_CAPITAL_A+digit);
101
10.1M
        } else {
102
10.1M
            return (char)(_SMALL_A+digit);
103
10.1M
        }
104
10.1M
    } else {
105
4.27M
        return (char)((_ZERO_-26)+digit);
106
4.27M
    }
107
14.4M
}
108
109
/**
110
 * basicToDigit[] contains the numeric value of a basic code
111
 * point (for use in representing integers) in the range 0 to
112
 * BASE-1, or -1 if b is does not represent a value.
113
 */
114
static const int8_t
115
basicToDigit[256]={
116
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
117
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
118
119
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
120
    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
121
122
    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
123
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
124
125
    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
126
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
127
128
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
129
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
130
131
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
132
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
133
134
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
135
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
136
137
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
138
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
139
};
140
141
static inline char
142
0
asciiCaseMap(char b, UBool uppercase) {
143
0
    if(uppercase) {
144
0
        if(_SMALL_A<=b && b<=_SMALL_Z) {
145
0
            b-=(_SMALL_A-_CAPITAL_A);
146
0
        }
147
0
    } else {
148
0
        if(_CAPITAL_A<=b && b<=_CAPITAL_Z) {
149
0
            b+=(_SMALL_A-_CAPITAL_A);
150
0
        }
151
0
    }
152
0
    return b;
153
0
}
154
155
/* Punycode-specific Bootstring code ---------------------------------------- */
156
157
/*
158
 * The following code omits the {parts} of the pseudo-algorithm in the spec
159
 * that are not used with the Punycode parameter set.
160
 */
161
162
/* Bias adaptation function. */
163
static int32_t
164
4.88M
adaptBias(int32_t delta, int32_t length, UBool firstTime) {
165
4.88M
    int32_t count;
166
167
4.88M
    if(firstTime) {
168
4.72M
        delta/=DAMP;
169
4.72M
    } else {
170
160k
        delta/=2;
171
160k
    }
172
173
4.88M
    delta+=delta/length;
174
4.94M
    for(count=0; delta>((BASE-TMIN)*TMAX)/2; count+=BASE) {
175
62.6k
        delta/=(BASE-TMIN);
176
62.6k
    }
177
178
4.88M
    return count+(((BASE-TMIN+1)*delta)/(delta+SKEW));
179
4.88M
}
180
181
9.76M
#define MAX_CP_COUNT    200
182
183
U_CFUNC int32_t
184
u_strToPunycode(const UChar *src, int32_t srcLength,
185
                UChar *dest, int32_t destCapacity,
186
                const UBool *caseFlags,
187
4.71M
                UErrorCode *pErrorCode) {
188
189
4.71M
    int32_t cpBuffer[MAX_CP_COUNT];
190
4.71M
    int32_t n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount;
191
4.71M
    UChar c, c2;
192
193
    /* argument checking */
194
4.71M
    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
195
0
        return 0;
196
0
    }
197
198
4.71M
    if(src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
199
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
200
0
        return 0;
201
0
    }
202
203
    /*
204
     * Handle the basic code points and
205
     * convert extended ones to UTF-32 in cpBuffer (caseFlag in sign bit):
206
     */
207
4.71M
    srcCPCount=destLength=0;
208
4.71M
    if(srcLength==-1) {
209
        /* NUL-terminated input */
210
0
        for(j=0; /* no condition */; ++j) {
211
0
            if((c=src[j])==0) {
212
0
                break;
213
0
            }
214
0
            if(srcCPCount==MAX_CP_COUNT) {
215
                /* too many input code points */
216
0
                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
217
0
                return 0;
218
0
            }
219
0
            if(IS_BASIC(c)) {
220
0
                cpBuffer[srcCPCount++]=0;
221
0
                if(destLength<destCapacity) {
222
0
                    dest[destLength]=
223
0
                        caseFlags!=NULL ?
224
0
                            asciiCaseMap((char)c, caseFlags[j]) :
225
0
                            (char)c;
226
0
                }
227
0
                ++destLength;
228
0
            } else {
229
0
                n=(caseFlags!=NULL && caseFlags[j])<<31L;
230
0
                if(U16_IS_SINGLE(c)) {
231
0
                    n|=c;
232
0
                } else if(U16_IS_LEAD(c) && U16_IS_TRAIL(c2=src[j+1])) {
233
0
                    ++j;
234
0
                    n|=(int32_t)U16_GET_SUPPLEMENTARY(c, c2);
235
0
                } else {
236
                    /* error: unmatched surrogate */
237
0
                    *pErrorCode=U_INVALID_CHAR_FOUND;
238
0
                    return 0;
239
0
                }
240
0
                cpBuffer[srcCPCount++]=n;
241
0
            }
242
0
        }
243
4.71M
    } else {
244
        /* length-specified input */
245
9.69M
        for(j=0; j<srcLength; ++j) {
246
4.97M
            if(srcCPCount==MAX_CP_COUNT) {
247
                /* too many input code points */
248
212
                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
249
212
                return 0;
250
212
            }
251
4.97M
            c=src[j];
252
4.97M
            if(IS_BASIC(c)) {
253
151k
                cpBuffer[srcCPCount++]=0;
254
151k
                if(destLength<destCapacity) {
255
129k
                    dest[destLength]=
256
129k
                        caseFlags!=NULL ?
257
0
                            asciiCaseMap((char)c, caseFlags[j]) :
258
129k
                            (char)c;
259
129k
                }
260
151k
                ++destLength;
261
4.82M
            } else {
262
4.82M
                n=(caseFlags!=NULL && caseFlags[j])<<31L;
263
4.82M
                if(U16_IS_SINGLE(c)) {
264
4.82M
                    n|=c;
265
4.82M
                } else if(U16_IS_LEAD(c) && (j+1)<srcLength && U16_IS_TRAIL(c2=src[j+1])) {
266
1.49k
                    ++j;
267
1.49k
                    n|=(int32_t)U16_GET_SUPPLEMENTARY(c, c2);
268
1.49k
                } else {
269
                    /* error: unmatched surrogate */
270
0
                    *pErrorCode=U_INVALID_CHAR_FOUND;
271
0
                    return 0;
272
0
                }
273
4.82M
                cpBuffer[srcCPCount++]=n;
274
4.82M
            }
275
4.97M
        }
276
4.71M
    }
277
278
    /* Finish the basic string - if it is not empty - with a delimiter. */
279
4.71M
    basicLength=destLength;
280
4.71M
    if(basicLength>0) {
281
57.3k
        if(destLength<destCapacity) {
282
57.1k
            dest[destLength]=DELIMITER;
283
57.1k
        }
284
57.3k
        ++destLength;
285
57.3k
    }
286
287
    /*
288
     * handledCPCount is the number of code points that have been handled
289
     * basicLength is the number of basic code points
290
     * destLength is the number of chars that have been output
291
     */
292
293
    /* Initialize the state: */
294
4.71M
    n=INITIAL_N;
295
4.71M
    delta=0;
296
4.71M
    bias=INITIAL_BIAS;
297
298
    /* Main encoding loop: */
299
9.50M
    for(handledCPCount=basicLength; handledCPCount<srcCPCount; /* no op */) {
300
        /*
301
         * All non-basic code points < n have been handled already.
302
         * Find the next larger one:
303
         */
304
11.1M
        for(m=0x7fffffff, j=0; j<srcCPCount; ++j) {
305
6.31M
            q=cpBuffer[j]&0x7fffffff; /* remove case flag from the sign bit */
306
6.31M
            if(n<=q && q<m) {
307
4.91M
                m=q;
308
4.91M
            }
309
6.31M
        }
310
311
        /*
312
         * Increase delta enough to advance the decoder's
313
         * <n,i> state to <m,0>, but guard against overflow:
314
         */
315
4.79M
        if(m-n>(0x7fffffff-MAX_CP_COUNT-delta)/(handledCPCount+1)) {
316
0
            *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
317
0
            return 0;
318
0
        }
319
4.79M
        delta+=(m-n)*(handledCPCount+1);
320
4.79M
        n=m;
321
322
        /* Encode a sequence of same code points n */
323
11.1M
        for(j=0; j<srcCPCount; ++j) {
324
6.31M
            q=cpBuffer[j]&0x7fffffff; /* remove case flag from the sign bit */
325
6.31M
            if(q<n) {
326
917k
                ++delta;
327
5.39M
            } else if(q==n) {
328
                /* Represent delta as a generalized variable-length integer: */
329
14.4M
                for(q=delta, k=BASE; /* no condition */; k+=BASE) {
330
331
                    /** RAM: comment out the old code for conformance with draft-ietf-idn-punycode-03.txt
332
333
                    t=k-bias;
334
                    if(t<TMIN) {
335
                        t=TMIN;
336
                    } else if(t>TMAX) {
337
                        t=TMAX;
338
                    }
339
                    */
340
341
14.4M
                    t=k-bias;
342
14.4M
                    if(t<TMIN) {
343
9.48M
                        t=TMIN;
344
9.48M
                    } else if(k>=(bias+TMAX)) {
345
4.88M
                        t=TMAX;
346
4.88M
                    }
347
348
14.4M
                    if(q<t) {
349
4.81M
                        break;
350
4.81M
                    }
351
352
9.60M
                    if(destLength<destCapacity) {
353
9.60M
                        dest[destLength]=digitToBasic(t+(q-t)%(BASE-t), 0);
354
9.60M
                    }
355
9.60M
                    ++destLength;
356
9.60M
                    q=(q-t)/(BASE-t);
357
9.60M
                }
358
359
4.81M
                if(destLength<destCapacity) {
360
4.81M
                    dest[destLength]=digitToBasic(q, (UBool)(cpBuffer[j]<0));
361
4.81M
                }
362
4.81M
                ++destLength;
363
4.81M
                bias=adaptBias(delta, handledCPCount+1, (UBool)(handledCPCount==basicLength));
364
4.81M
                delta=0;
365
4.81M
                ++handledCPCount;
366
4.81M
            }
367
6.31M
        }
368
369
4.79M
        ++delta;
370
4.79M
        ++n;
371
4.79M
    }
372
373
4.71M
    return u_terminateUChars(dest, destCapacity, destLength, pErrorCode);
374
4.71M
}
375
376
U_CFUNC int32_t
377
u_strFromPunycode(const UChar *src, int32_t srcLength,
378
                  UChar *dest, int32_t destCapacity,
379
                  UBool *caseFlags,
380
10.8k
                  UErrorCode *pErrorCode) {
381
10.8k
    int32_t n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t,
382
10.8k
            destCPCount, firstSupplementaryIndex, cpLength;
383
10.8k
    UChar b;
384
385
    /* argument checking */
386
10.8k
    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
387
0
        return 0;
388
0
    }
389
390
10.8k
    if(src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
391
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
392
0
        return 0;
393
0
    }
394
395
10.8k
    if(srcLength==-1) {
396
0
        srcLength=u_strlen(src);
397
0
    }
398
399
    /*
400
     * Handle the basic code points:
401
     * Let basicLength be the number of input code points
402
     * before the last delimiter, or 0 if there is none,
403
     * then copy the first basicLength code points to the output.
404
     *
405
     * The two following loops iterate backward.
406
     */
407
118k
    for(j=srcLength; j>0;) {
408
110k
        if(src[--j]==DELIMITER) {
409
3.09k
            break;
410
3.09k
        }
411
110k
    }
412
10.8k
    destLength=basicLength=destCPCount=j;
413
10.8k
    U_ASSERT(destLength>=0);
414
415
13.2k
    while(j>0) {
416
4.40k
        b=src[--j];
417
4.40k
        if(!IS_BASIC(b)) {
418
2.02k
            *pErrorCode=U_INVALID_CHAR_FOUND;
419
2.02k
            return 0;
420
2.02k
        }
421
422
2.38k
        if(j<destCapacity) {
423
1.88k
            dest[j]=(UChar)b;
424
425
1.88k
            if(caseFlags!=NULL) {
426
0
                caseFlags[j]=IS_BASIC_UPPERCASE(b);
427
0
            }
428
1.88k
        }
429
2.38k
    }
430
431
    /* Initialize the state: */
432
8.80k
    n=INITIAL_N;
433
8.80k
    i=0;
434
8.80k
    bias=INITIAL_BIAS;
435
8.80k
    firstSupplementaryIndex=1000000000;
436
437
    /*
438
     * Main decoding loop:
439
     * Start just after the last delimiter if any
440
     * basic code points were copied; start at the beginning otherwise.
441
     */
442
72.8k
    for(in=basicLength>0 ? basicLength+1 : 0; in<srcLength; /* no op */) {
443
        /*
444
         * in is the index of the next character to be consumed, and
445
         * destCPCount is the number of code points in the output array.
446
         *
447
         * Decode a generalized variable-length integer into delta,
448
         * which gets added to i.  The overflow checking is easier
449
         * if we increase i as we go, then subtract off its starting
450
         * value at the end to obtain delta.
451
         */
452
100k
        for(oldi=i, w=1, k=BASE; /* no condition */; k+=BASE) {
453
100k
            if(in>=srcLength) {
454
537
                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
455
537
                return 0;
456
537
            }
457
458
100k
            digit=basicToDigit[(uint8_t)src[in++]];
459
100k
            if(digit<0) {
460
1.49k
                *pErrorCode=U_INVALID_CHAR_FOUND;
461
1.49k
                return 0;
462
1.49k
            }
463
98.7k
            if(digit>(0x7fffffff-i)/w) {
464
                /* integer overflow */
465
217
                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
466
217
                return 0;
467
217
            }
468
469
98.5k
            i+=digit*w;
470
            /** RAM: comment out the old code for conformance with draft-ietf-idn-punycode-03.txt  
471
            t=k-bias;
472
            if(t<TMIN) {
473
                t=TMIN;
474
            } else if(t>TMAX) {
475
                t=TMAX;
476
            }
477
            */
478
98.5k
            t=k-bias;
479
98.5k
            if(t<TMIN) {
480
13.5k
                t=TMIN;
481
85.0k
            } else if(k>=(bias+TMAX)) {
482
70.1k
                t=TMAX;
483
70.1k
            }
484
98.5k
            if(digit<t) {
485
64.9k
                break;
486
64.9k
            }
487
488
33.5k
            if(w>0x7fffffff/(BASE-t)) {
489
                /* integer overflow */
490
0
                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
491
0
                return 0;
492
0
            }
493
33.5k
            w*=BASE-t;
494
33.5k
        }
495
496
        /*
497
         * Modification from sample code:
498
         * Increments destCPCount here,
499
         * where needed instead of in for() loop tail.
500
         */
501
64.9k
        ++destCPCount;
502
64.9k
        bias=adaptBias(i-oldi, destCPCount, (UBool)(oldi==0));
503
504
        /*
505
         * i was supposed to wrap around from (incremented) destCPCount to 0,
506
         * incrementing n each time, so we'll fix that now:
507
         */
508
64.9k
        if(i/destCPCount>(0x7fffffff-n)) {
509
            /* integer overflow */
510
203
            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
511
203
            return 0;
512
203
        }
513
514
64.7k
        n+=i/destCPCount;
515
64.7k
        i%=destCPCount;
516
        /* not needed for Punycode: */
517
        /* if (decode_digit(n) <= BASE) return punycode_invalid_input; */
518
519
64.7k
        if(n>0x10ffff || U_IS_SURROGATE(n)) {
520
            /* Unicode code point overflow */
521
710
            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
522
710
            return 0;
523
710
        }
524
525
        /* Insert n at position i of the output: */
526
64.0k
        cpLength=U16_LENGTH(n);
527
64.0k
        if(dest!=NULL && ((destLength+cpLength)<=destCapacity)) {
528
53.1k
            int32_t codeUnitIndex;
529
530
            /*
531
             * Handle indexes when supplementary code points are present.
532
             *
533
             * In almost all cases, there will be only BMP code points before i
534
             * and even in the entire string.
535
             * This is handled with the same efficiency as with UTF-32.
536
             *
537
             * Only the rare cases with supplementary code points are handled
538
             * more slowly - but not too bad since this is an insertion anyway.
539
             */
540
53.1k
            if(i<=firstSupplementaryIndex) {
541
32.6k
                codeUnitIndex=i;
542
32.6k
                if(cpLength>1) {
543
2.89k
                    firstSupplementaryIndex=codeUnitIndex;
544
29.7k
                } else {
545
29.7k
                    ++firstSupplementaryIndex;
546
29.7k
                }
547
32.6k
            } else {
548
20.5k
                codeUnitIndex=firstSupplementaryIndex;
549
20.5k
                U16_FWD_N(dest, codeUnitIndex, destLength, i-codeUnitIndex);
550
20.5k
            }
551
552
            /* use the UChar index codeUnitIndex instead of the code point index i */
553
53.1k
            if(codeUnitIndex<destLength) {
554
33.8k
                uprv_memmove(dest+codeUnitIndex+cpLength,
555
33.8k
                             dest+codeUnitIndex,
556
33.8k
                             (destLength-codeUnitIndex)*U_SIZEOF_UCHAR);
557
33.8k
                if(caseFlags!=NULL) {
558
0
                    uprv_memmove(caseFlags+codeUnitIndex+cpLength,
559
0
                                 caseFlags+codeUnitIndex,
560
0
                                 destLength-codeUnitIndex);
561
0
                }
562
33.8k
            }
563
53.1k
            if(cpLength==1) {
564
                /* BMP, insert one code unit */
565
29.7k
                dest[codeUnitIndex]=(UChar)n;
566
29.7k
            } else {
567
                /* supplementary character, insert two code units */
568
23.4k
                dest[codeUnitIndex]=U16_LEAD(n);
569
23.4k
                dest[codeUnitIndex+1]=U16_TRAIL(n);
570
23.4k
            }
571
53.1k
            if(caseFlags!=NULL) {
572
                /* Case of last character determines uppercase flag: */
573
0
                caseFlags[codeUnitIndex]=IS_BASIC_UPPERCASE(src[in-1]);
574
0
                if(cpLength==2) {
575
0
                    caseFlags[codeUnitIndex+1]=FALSE;
576
0
                }
577
0
            }
578
53.1k
        }
579
64.0k
        destLength+=cpLength;
580
64.0k
        U_ASSERT(destLength>=0);
581
64.0k
        ++i;
582
64.0k
    }
583
584
5.64k
    return u_terminateUChars(dest, destCapacity, destLength, pErrorCode);
585
8.80k
}
586
587
/* ### check notes on overflow handling - only necessary if not IDNA? are these Punycode functions to be public? */
588
589
#endif /* #if !UCONFIG_NO_IDNA */