Diff
Not logged in

Differences From Artifact [4f3603d99e]:

To Artifact [9d407eb301]:


79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
79
80
81
82
83
84
85

86
87

88
89
90
91
92
93
94







-
+

-







};

/*
 * Functions used only in this module.
 */

static int		UtfCount(int ch);
static int		Invalid(unsigned char *src);
static int		Invalid(const char *src);
static int		UCS4ToUpper(int ch);
static int		UCS4ToLower(int ch);
static int		UCS4ToTitle(int ch);

/*
 *---------------------------------------------------------------------------
 *
 * UtfCount --
 *
123
124
125
126
127
128
129
130
131
132





133
134
135
136
137
138











139
140
141
142
143
144
145
122
123
124
125
126
127
128



129
130
131
132
133


134



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152







-
-
-
+
+
+
+
+
-
-

-
-
-
+
+
+
+
+
+
+
+
+
+
+







}

/*
 *---------------------------------------------------------------------------
 *
 * Invalid --
 *
 *	Utility routine to report whether /src/ points to the start of an
 *	invald byte sequence that should be rejected. This might be because
 *	it is an overlong encoding, or because it encodes something out of
 *	Given a pointer to a two-byte prefix of a well-formed UTF-8 byte
 *	sequence (a lead byte followed by a trail byte) this routine
 *	examines those two bytes to determine whether the sequence is
 *	invalid in UTF-8.  This might be because it is an overlong
 *	encoding, or because it encodes something out of the proper range.
 *	the proper range. Caller guarantees that src[0] and src[1] are
 *	readable, and
 *
 *	(src[0] >= 0xC0) && (src[0] != 0xC1)
 * 	(src[1] >= 0x80) && (src[1] < 0xC0)
 *	(src[0] < ((TCL_UTF_MAX > 3) ? 0xF5 : 0xF0))
 *	Given a pointer to the bytes \xF8 or \xFC , this routine will
 *	try to read beyond the end of the "bounds" table.  Callers must
 *	prevent this.
 *
 *	Given a pointer to something else (an ASCII byte, a trail byte,
 *	or another byte	that can never begin a valid byte sequence such
 *	as \xF5) this routine returns false.  That makes the routine poorly
 *	named, as it does not detect and report all invalid sequences.
 *
 *	Callers have to take care that this routine does something useful
 *	for their needs.
 *
 * Results:
 *	A boolean.
 *---------------------------------------------------------------------------
 */

static const unsigned char bounds[28] = {
155
156
157
158
159
160
161
162

163
164

165
166
167
168
169
170
171
172

173
174
175
176
177
178
179
162
163
164
165
166
167
168

169
170

171
172
173
174
175
176
177
178

179
180
181
182
183
184
185
186







-
+

-
+







-
+







    0xC0, 0xBF,	/* Not used, but reject all again for safety. */
    0xC0, 0xBF	/* Not used, but reject all again for safety. */
#endif
};

static int
Invalid(
    unsigned char *src)	/* Points to lead byte of a UTF-8 byte sequence */
    const char *src)	/* Points to lead byte of a UTF-8 byte sequence */
{
    unsigned char byte = *src;
    unsigned char byte = UCHAR(*src);
    int index;

    if ((byte & 0xC3) != 0xC0) {
	/* Only lead bytes 0xC0, 0xE0, 0xF0, 0xF4 need examination */
	return 0;
    }
    index = (byte - 0xC0) >> 1;
    if (src[1] < bounds[index] || src[1] > bounds[index+1]) {
    if (UCHAR(src[1]) < bounds[index] || UCHAR(src[1]) > bounds[index+1]) {
	/* Out of bounds - report invalid. */
	return 1;
    }
    return 0;
}

/*
362
363
364
365
366
367
368
369

370
371
372
373
374
375
376
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383







-
+







{
    Tcl_UniChar byte;

    /*
     * Unroll 1 to 3 (or 4) byte UTF-8 sequences.
     */

    byte = *((unsigned char *) src);
    byte = UCHAR(*src);
    if (byte < 0xC0) {
	/*
	 * Handles properly formed UTF-8 characters between 0x01 and 0x7F.
	 * Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
	 * characters representing themselves.
	 */

484
485
486
487
488
489
490
491

492




493
494
495
496
497
498
499
500
501
502
503
504
505
506

507
508
509
510
511
512







513
514
515
516
517

518
519
520
521

522
523
524
525
526
527

528
529
530
531
532
533
534
491
492
493
494
495
496
497

498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516

517
518
519
520
521


522
523
524
525
526
527
528
529
530
531


532




533


534
535
536

537
538
539
540
541
542
543
544







-
+

+
+
+
+













-
+




-
-
+
+
+
+
+
+
+



-
-
+
-
-
-
-
+
-
-



-
+







    int length,			/* Length of UTF-8 string in bytes, or -1 for
				 * strlen(). */
    Tcl_DString *dsPtr)		/* Unicode representation of string is
				 * appended to this previously initialized
				 * DString. */
{
    Tcl_UniChar ch = 0, *w, *wString;
    const char *p, *end;
    const char *p;
    int oldLength;
    /* Pointer to the end of string. Never read endPtr[0] */
    const char *endPtr = src + length;
    /* Pointer to last byte where optimization still can be used */
    const char *optPtr = endPtr - TCL_UTF_MAX;

    if (length < 0) {
	length = strlen(src);
    }

    /*
     * Unicode string length in Tcl_UniChars will be <= UTF-8 string length in
     * bytes.
     */

    oldLength = Tcl_DStringLength(dsPtr);

    Tcl_DStringSetLength(dsPtr,
	    oldLength + (int) ((length + 1) * sizeof(Tcl_UniChar)));
	    oldLength + ((length + 1) * sizeof(Tcl_UniChar)));
    wString = (Tcl_UniChar *) (Tcl_DStringValue(dsPtr) + oldLength);

    w = wString;
    p = src;
    end = src + length - TCL_UTF_MAX;
    while (p < end) {
    endPtr = src + length;
    optPtr = endPtr - TCL_UTF_MAX;
    while (p <= optPtr) {
	p += TclUtfToUniChar(p, &ch);
	*w++ = ch;
    }
    while ((p < endPtr) && Tcl_UtfCharComplete(p, endPtr-p)) {
	p += TclUtfToUniChar(p, &ch);
	*w++ = ch;
    }
    end += TCL_UTF_MAX;
    while (p < end) {
    while (p < endPtr) {
	if (Tcl_UtfCharComplete(p, end-p)) {
	    p += TclUtfToUniChar(p, &ch);
	} else {
	    ch = UCHAR(*p++);
	*w++ = UCHAR(*p++);
	}
	*w++ = ch;
    }
    *w = '\0';
    Tcl_DStringSetLength(dsPtr,
	    (oldLength + ((char *) w - (char *) wString)));
	    oldLength + ((char *) w - (char *) wString));

    return wString;
}

/*
 *---------------------------------------------------------------------------
 *
574
575
576
577
578
579
580
581
582


583
584
585
586
587
588
589
590
591
592
593
594

595

596
597
598
599
600



601



602







603


604
605
606
607
608
609
610
611
612
613
614

615
616
617
618
619
620
621
622
623
624
625
626




627
628
629
630
631
632
633
584
585
586
587
588
589
590


591
592
593
594
595
596







597
598

599
600
601
602

603
604
605
606

607
608
609
610
611
612
613
614
615
616
617

618
619
620
621
622
623
624
625
626
627
628
629

630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653







-
-
+
+




-
-
-
-
-
-
-

+
-
+



-

+
+
+
-
+
+
+

+
+
+
+
+
+
+
-
+
+










-
+












+
+
+
+







 *
 *---------------------------------------------------------------------------
 */

int
Tcl_NumUtfChars(
    const char *src,	/* The UTF-8 string to measure. */
    int length)			/* The length of the string in bytes, or -1
				 * for strlen(string). */
    int length)		/* The length of the string in bytes, or -1
			 * for strlen(string). */
{
    Tcl_UniChar ch = 0;
    int i = 0;

    /*
     * The separate implementations are faster.
     *
     * Since this is a time-sensitive function, we also do the check for the
     * single-byte char case specially.
     */

    if (length < 0) {
	/* string is NUL-terminated, so TclUtfToUniChar calls are safe. */
	while (*src != '\0') {
	while ((*src != '\0') && (i < INT_MAX)) {
	    src += TclUtfToUniChar(src, &ch);
	    i++;
	}
	if (i < 0) i = INT_MAX; /* Bug [2738427] */
    } else {
	/* Will return value between 0 and length. No overflow checks. */

	/* Pointer to the end of string. Never read endPtr[0] */
	const char *endPtr = src + length - TCL_UTF_MAX;
	const char *endPtr = src + length;
	/* Pointer to last byte where optimization still can be used */
	const char *optPtr = endPtr - TCL_UTF_MAX;

	/*
	 * Optimize away the call in this loop. Justified because...
	 * when (src <= optPtr), (endPtr - src) >= (endPtr - optPtr)
	 * By initialization above (endPtr - optPtr) = TCL_UTF_MAX
	 * So (endPtr - src) >= TCL_UTF_MAX, and passing that to
	 * Tcl_UtfCharComplete we know will cause return of 1.
	 */
	while (src < endPtr) {
	while (src <= optPtr
		/* && Tcl_UtfCharComplete(src, endPtr - src) */ ) {
#if TCL_UTF_MAX < 4
	    if (((unsigned)UCHAR(*src) - 0xF0) < 5) {
		/* treat F0 - F4 as single character */
		ch = 0;
		src++;
	    } else
#endif
	    src += TclUtfToUniChar(src, &ch);
	    i++;
	}
	endPtr += TCL_UTF_MAX;
	/* Loop over the remaining string where call must happen */
	while ((src < endPtr) && Tcl_UtfCharComplete(src, endPtr - src)) {
#if TCL_UTF_MAX < 4
	    if (((unsigned)UCHAR(*src) - 0xF0) < 5) {
		/* treat F0 - F4 as single character */
		ch = 0;
		src++;
	    } else
#endif
	    src += TclUtfToUniChar(src, &ch);
	    i++;
	}
	if (src < endPtr) {
	    /*
	     * String ends in an incomplete UTF-8 sequence.
	     * Count every byte in it.
	     */
	    i += endPtr - src;
	}
    }
    return i;
}

/*
651
652
653
654
655
656
657
658

659
660

661
662
663
664
665
666
667
671
672
673
674
675
676
677

678
679

680
681
682
683
684
685
686
687







-
+

-
+








const char *
Tcl_UtfFindFirst(
    const char *src,		/* The UTF-8 string to be searched. */
    int ch)			/* The Unicode character to search for. */
{
    while (1) {
	int ucs4, len = TclUtfToUCS4(src, &ucs4);
	int find, len = TclUtfToUCS4(src, &find);

	if (ucs4 == ch) {
	if (find == ch) {
	    return src;
	}
	if (*src == '\0') {
	    return NULL;
	}
	src += len;
    }
690
691
692
693
694
695
696
697

698
699

700
701
702
703
704
705
706
710
711
712
713
714
715
716

717
718

719
720
721
722
723
724
725
726







-
+

-
+







Tcl_UtfFindLast(
    const char *src,		/* The UTF-8 string to be searched. */
    int ch)			/* The Unicode character to search for. */
{
    const char *last = NULL;

    while (1) {
	int ucs4, len = TclUtfToUCS4(src, &ucs4);
	int find, len = TclUtfToUCS4(src, &find);

	if (ucs4 == ch) {
	if (find == ch) {
	    last = src;
	}
	if (*src == '\0') {
	    break;
	}
	src += len;
    }
728
729
730
731
732
733
734
735
736


737


738
739
740
741
742
743
744
745
746
747
748







749

750
751
752
753
754
755
756
748
749
750
751
752
753
754


755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777

778
779
780
781
782
783
784
785







-
-
+
+

+
+











+
+
+
+
+
+
+
-
+







 *---------------------------------------------------------------------------
 */

const char *
Tcl_UtfNext(
    const char *src)		/* The current location in the string. */
{
    int left = totalBytes[UCHAR(*src)];
    const char *next = src + 1;
    int left;
    const char *next;

    left = totalBytes[UCHAR(*src)];
    next = src + 1;
    while (--left) {
	if ((*next & 0xC0) != 0x80) {
	    /*
	     * src points to non-trail byte; We ran out of trail bytes
	     * before the needs of the lead byte were satisfied.
	     * Let the (malformed) lead byte alone be a character
	     */
	    return src + 1;
	}
	next++;
    }
    /*
     * Call Invalid() here only if required conditions are met:
     *    src[0] is known a lead byte.
     *    src[1] is known a trail byte.
     * Especially important to prevent calls when src[0] == '\xF8' or '\xFC'
     * See tests utf-6.37 through utf-6.43 through valgrind or similar tool.
     */
    if (Invalid((unsigned char *)src)) {
    if ((next == src + 1) || Invalid(src)) {
	return src + 1;
    }
    return next;
}

/*
 *---------------------------------------------------------------------------
779
780
781
782
783
784
785
786

787
788
789
790
791
792
793
794
795

796
797
798
799
800
801
802
808
809
810
811
812
813
814

815
816
817
818
819
820
821
822
823

824
825
826
827
828
829
830
831







-
+








-
+







    const char *start)		/* Pointer to the beginning of the string */
{
    int trailBytesSeen = 0;	/* How many trail bytes have been verified? */
    const char *fallback = src - 1;
				/* If we cannot find a lead byte that might
				 * start a prefix of a valid UTF byte sequence,
				 * we will fallback to a one-byte back step */
    unsigned char *look = (unsigned char *)fallback;
    const char *look = fallback;
				/* Start search at the fallback position */

    /* Quick boundary case exit. */
    if (fallback <= start) {
	return start;
    }

    do {
	unsigned char byte = look[0];
	unsigned char byte = UCHAR(look[0]);

	if (byte < 0x80) {
	    /*
	     * Single byte character. Either this is a correct previous
	     * character, or it is followed by at least one trail byte
	     * which indicates a malformed sequence. In either case the
	     * correct result is to return the fallback.
824
825
826
827
828
829
830
831

832
833
834
835
836
837
838
853
854
855
856
857
858
859

860
861
862
863
864
865
866
867







-
+







		 * return the fallback location. See test utf-7.17
		 */
		return fallback;
	    }

	    /*
	     * trailBytesSeen > 0, so we can examine look[1] safely.
	     * Use that capability to screen out overlong sequences.
	     * Use that capability to screen out invalid sequences.
	     */

	    if (Invalid(look)) {
		/* Reject */
		return fallback;
	    }
	    return (const char *)look;
851
852
853
854
855
856
857
858

859
860
861

862
863

864
865
866

867
868
869

870
871
872
873
874
875
876
880
881
882
883
884
885
886

887
888
889

890
891

892
893
894

895
896
897

898
899
900
901
902
903
904
905







-
+


-
+

-
+


-
+


-
+







	     * and exit this loop before we run past the start of the string.
	     */
	    return fallback;
	}

	/* Continue the search backwards... */
	look--;
    } while (trailBytesSeen < ((TCL_UTF_MAX > 3) ? 4 : 3));
    } while (trailBytesSeen < ((TCL_UTF_MAX > 4) ? 4 : 3));

    /*
     * We've seen TCL_UTF_MAX trail bytes, so we know there will not be a
     * We've seen 3 (or 4) trail bytes, so we know there will not be a
     * properly formed byte sequence to find, and we can stop looking,
     * accepting the fallback (for TCL_UTF_MAX > 3) or just go back as
     * accepting the fallback (for TCL_UTF_MAX > 4) or just go back as
     * far as we can.
     */
#if TCL_UTF_MAX > 3
#if TCL_UTF_MAX > 4
    return fallback;
#else
    return src - TCL_UTF_MAX;
    return src - 3;
#endif
}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_UniCharAtIndex --
1071
1072
1073
1074
1075
1076
1077
1078

1079
1080
1081
1082
1083
1084
1085
1100
1101
1102
1103
1104
1105
1106

1107
1108
1109
1110
1111
1112
1113
1114







-
+







    /*
     * Iterate over the string until we hit the terminating null.
     */

    src = dst = str;
    while (*src) {
	len = TclUtfToUCS4(src, &ch);
	lowChar = UCS4ToLower(ch);
	lowChar = TclUCS4ToLower(ch);

	/*
	 * To keep badly formed Utf strings from getting inflated by the
	 * conversion (thereby causing a segfault), only copy the lower case
	 * char to dst if its size is <= the original char.
	 */

1142
1143
1144
1145
1146
1147
1148
1149

1150
1151
1152
1153
1154
1155
1156
1171
1172
1173
1174
1175
1176
1177

1178
1179
1180
1181
1182
1183
1184
1185







-
+







	src += len;
    }
    while (*src) {
	len = TclUtfToUCS4(src, &ch);
	lowChar = ch;
	/* Special exception for Georgian Asomtavruli chars, no titlecase. */
	if ((unsigned)(lowChar - 0x1C90) >= 0x30) {
	    lowChar = UCS4ToLower(lowChar);
	    lowChar = TclUCS4ToLower(lowChar);
	}

	if (len < UtfCount(lowChar) || ((lowChar & ~0x7FF) == 0xD800)) {
	    memmove(dst, src, len);
	    dst += len;
	} else {
	    dst += Tcl_UniCharToUtf(lowChar, dst);
1247
1248
1249
1250
1251
1252
1253
1254
1255


1256
1257
1258

1259
1260
1261
1262
1263
1264
1265
1276
1277
1278
1279
1280
1281
1282


1283
1284
1285
1286

1287
1288
1289
1290
1291
1292
1293
1294







-
-
+
+


-
+







	 */

	cs += TclUtfToUniChar(cs, &ch1);
	ct += TclUtfToUniChar(ct, &ch2);
	if (ch1 != ch2) {
#if TCL_UTF_MAX == 4
	    /* Surrogates always report higher than non-surrogates */
	    if (((ch1 & 0xFC00) == 0xD800)) {
	    if ((ch2 & 0xFC00) != 0xD800) {
	    if (((ch1 & ~0x3FF) == 0xD800)) {
	    if ((ch2 & ~0x3FF) != 0xD800) {
		return ch1;
	    }
	    } else if ((ch2 & 0xFC00) == 0xD800) {
	    } else if ((ch2 & ~0x3FF) == 0xD800) {
		return -ch2;
	    }
#endif
	    return (ch1 - ch2);
	}
    }
    return 0;
1420
1421
1422
1423
1424
1425
1426
1427
1428


1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447

1448
1449
1450
1451
1452
1453
1454
1449
1450
1451
1452
1453
1454
1455


1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475

1476
1477
1478
1479
1480
1481
1482
1483







-
-
+
+


















-
+







 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static int
UCS4ToLower(
int
TclUCS4ToLower(
    int ch)			/* Unicode character to convert. */
{
    if (!UNICODE_OUT_OF_RANGE(ch)) {
	int info = GetUniCharInfo(ch);
	int mode = GetCaseType(info);

	if ((mode & 0x02) && (mode != 0x7)) {
	    ch += GetDelta(info);
	}
    }
    /* Clear away extension bits, if any */
    return ch & 0x1FFFFF;
}

Tcl_UniChar
Tcl_UniCharToLower(
    int ch)			/* Unicode character to convert. */
{
    return (Tcl_UniChar) UCS4ToLower(ch);
    return (Tcl_UniChar) TclUCS4ToLower(ch);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_UniCharToTitle --
 *