Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abacbb320b | ||
|
|
fac62d70e3 | ||
|
|
f6278d14a3 | ||
|
|
f4b66be2ec | ||
|
|
8f1c3cd0e5 | ||
|
|
fb201ad904 | ||
|
|
8c522d9c41 | ||
|
|
b76a882c7a | ||
|
|
116a9a7f78 | ||
|
|
b798e429f8 | ||
|
|
60fc9fe4c5 | ||
|
|
1770558983 |
+606
-474
File diff suppressed because it is too large
Load Diff
+206
-42
@@ -66,7 +66,7 @@ static CONST unsigned char totalBytes[256] = {
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
#if TCL_UTF_MAX > 3
|
||||
4,4,4,4,4,4,4,4,
|
||||
@@ -81,6 +81,7 @@ static CONST unsigned char totalBytes[256] = {
|
||||
*/
|
||||
|
||||
static int UtfCount(int ch);
|
||||
static int Invalid(unsigned char *src);
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
@@ -115,7 +116,61 @@ UtfCount(
|
||||
#endif
|
||||
return 3;
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* 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))
|
||||
*
|
||||
* Results:
|
||||
* A boolean.
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static CONST unsigned char bounds[28] = {
|
||||
0x80, 0x80, /* \xC0 accepts \x80 only */
|
||||
0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF,
|
||||
0x80, 0xBF, /* (\xC4 - \xDC) -- all sequences valid */
|
||||
0xA0, 0xBF, /* \xE0\x80 through \xE0\x9F are invalid prefixes */
|
||||
0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, /* (\xE4 - \xEC) -- all valid */
|
||||
#if TCL_UTF_MAX > 3
|
||||
0x90, 0xBF, /* \xF0\x80 through \xF0\x8F are invalid prefixes */
|
||||
0x80, 0x8F /* \xF4\x90 and higher are invalid prefixes */
|
||||
#else
|
||||
0xC0, 0xBF, /* Not used, but reject all again for safety. */
|
||||
0xC0, 0xBF /* Not used, but reject all again for safety. */
|
||||
#endif
|
||||
};
|
||||
|
||||
INLINE static int
|
||||
Invalid(
|
||||
unsigned char *src) /* Points to lead byte of a UTF-8 byte sequence */
|
||||
{
|
||||
unsigned char byte = *src;
|
||||
int index;
|
||||
|
||||
if (byte % 0x04) {
|
||||
/* 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]) {
|
||||
/* Out of bounds - report invalid. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
@@ -154,7 +209,7 @@ Tcl_UniCharToUtf(
|
||||
return 2;
|
||||
}
|
||||
if (ch <= 0xFFFF) {
|
||||
#if TCL_UTF_MAX == 4
|
||||
#if 0 && TCL_UTF_MAX == 4
|
||||
if ((ch & 0xF800) == 0xD800) {
|
||||
if (ch & 0x0400) {
|
||||
/* Low surrogate */
|
||||
@@ -464,7 +519,6 @@ Tcl_NumUtfChars(
|
||||
* for strlen(string). */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
register Tcl_UniChar *chPtr = &ch;
|
||||
register int i;
|
||||
|
||||
/*
|
||||
@@ -477,23 +531,25 @@ Tcl_NumUtfChars(
|
||||
i = 0;
|
||||
if (length < 0) {
|
||||
while (*src != '\0') {
|
||||
src += TclUtfToUniChar(src, chPtr);
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
i++;
|
||||
}
|
||||
if (i < 0) i = INT_MAX; /* Bug [2738427] */
|
||||
} else {
|
||||
register int n;
|
||||
register const char *endPtr = src + length - TCL_UTF_MAX;
|
||||
|
||||
while (length > 0) {
|
||||
if (UCHAR(*src) < 0xC0) {
|
||||
length--;
|
||||
src++;
|
||||
} else {
|
||||
n = Tcl_UtfToUniChar(src, chPtr);
|
||||
length -= n;
|
||||
src += n;
|
||||
}
|
||||
while (src < endPtr) {
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
i++;
|
||||
}
|
||||
endPtr += TCL_UTF_MAX;
|
||||
while ((src < endPtr) && Tcl_UtfCharComplete(src, endPtr - src)) {
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
i++;
|
||||
}
|
||||
if (src < endPtr) {
|
||||
i += endPtr - src;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -602,9 +658,26 @@ CONST char *
|
||||
Tcl_UtfNext(
|
||||
CONST char *src) /* The current location in the string. */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
int byte = *((unsigned char *) src);
|
||||
int left = totalBytes[byte];
|
||||
const char *next = src + 1;
|
||||
|
||||
return src + TclUtfToUniChar(src, &ch);
|
||||
while (--left) {
|
||||
byte = *((unsigned char *) next);
|
||||
if ((byte & 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++;
|
||||
}
|
||||
if (Invalid((unsigned char *)src)) {
|
||||
return src + 1;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -612,15 +685,43 @@ Tcl_UtfNext(
|
||||
*
|
||||
* Tcl_UtfPrev --
|
||||
*
|
||||
* Given a pointer to some current location in a UTF-8 string, move
|
||||
* backwards one character. This works correctly when the pointer is in
|
||||
* the middle of a UTF-8 character.
|
||||
* The aim of this routine is to provide a way to move backward
|
||||
* through a UTF-8 string. The caller is expected to pass non-NULL
|
||||
* pointer arguments start and src. start points to the beginning
|
||||
* of a string, and src >= start points to a location within (or just
|
||||
* past the end) of the string. This routine always returns a
|
||||
* pointer within the string (>= start). When (src == start), it
|
||||
* returns start. When (src > start), it returns a pointer (< src)
|
||||
* and (>= src - TCL_UTF_MAX). Subject to these constraints, the
|
||||
* routine returns a pointer to the earliest byte in the string that
|
||||
* starts a character when characters are read starting at start and
|
||||
* that character might include the byte src[-1]. The routine will
|
||||
* examine only those bytes in the range that might be returned.
|
||||
* It will not examine the byte *src, and because of that cannot
|
||||
* determine for certain in all circumstances whether the character
|
||||
* that begins with the returned pointer will or will not include
|
||||
* the byte src[-1]. In the scenario, where src points to the end of
|
||||
* a buffer being filled, the returned pointer point to either the
|
||||
* final complete character in the string or to the earliest byte
|
||||
* that might start an incomplete character waiting for more bytes to
|
||||
* complete.
|
||||
*
|
||||
* Because this routine always returns a value < src until the point
|
||||
* it is forced to return start, it is useful as a backward iterator
|
||||
* through a string that will always make progress and always be
|
||||
* prevented from running past the beginning of the string.
|
||||
*
|
||||
* In a string where all characters are complete and properly formed,
|
||||
* and the value of src points to the first byte of a character,
|
||||
* repeated Tcl_UtfPrev calls will step to the starting bytes of
|
||||
* characters, one character at a time. Within those limitations,
|
||||
* Tcl_UtfPrev and Tcl_UtfNext are inverses. If either condition cannot
|
||||
* be met, Tcl_UtfPrev and Tcl_UtfNext may not function as inverses and
|
||||
* the caller will have to take greater care.
|
||||
*
|
||||
* Results:
|
||||
* The return value is a pointer to the previous character in the UTF-8
|
||||
* string. If the current location was already at the beginning of the
|
||||
* string, the return value will also be a pointer to the beginning of
|
||||
* the string.
|
||||
* A pointer to the start of a character in the string as described
|
||||
* above.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
@@ -630,32 +731,95 @@ Tcl_UtfNext(
|
||||
|
||||
CONST char *
|
||||
Tcl_UtfPrev(
|
||||
CONST char *src, /* The current location in the string. */
|
||||
CONST char *start) /* Pointer to the beginning of the string, to
|
||||
* avoid going backwards too far. */
|
||||
CONST char *src, /* A location in a UTF-8 string. */
|
||||
CONST char *start) /* Pointer to the beginning of the string */
|
||||
{
|
||||
CONST char *look;
|
||||
int i, byte;
|
||||
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;
|
||||
/* Start search at the fallback position */
|
||||
|
||||
/* Quick boundary case exit. */
|
||||
if (fallback <= start) {
|
||||
return start;
|
||||
}
|
||||
|
||||
do {
|
||||
unsigned char byte = look[0];
|
||||
|
||||
src--;
|
||||
look = src;
|
||||
for (i = 0; i < TCL_UTF_MAX; i++) {
|
||||
if (look < start) {
|
||||
if (src < start) {
|
||||
src = start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
byte = *((unsigned char *) look);
|
||||
if (byte < 0x80) {
|
||||
break;
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
return fallback;
|
||||
}
|
||||
if (byte >= 0xC0) {
|
||||
return look;
|
||||
/* Non-trail byte; May be multibyte lead. */
|
||||
|
||||
if ((trailBytesSeen == 0)
|
||||
/*
|
||||
* We've seen no trailing context to use to check
|
||||
* anything. From what we know, this non-trail byte
|
||||
* is a prefix of a previous character, and accepting
|
||||
* it (the fallback) is correct.
|
||||
*/
|
||||
|
||||
|| (trailBytesSeen >= totalBytes[byte])) {
|
||||
/*
|
||||
* That is, (1 + trailBytesSeen > needed).
|
||||
* We've examined more bytes than needed to complete
|
||||
* this lead byte. No matter about well-formedness or
|
||||
* validity, the sequence starting with this lead byte
|
||||
* will never include the fallback location, so we must
|
||||
* 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 invalid sequences.
|
||||
*/
|
||||
|
||||
if (Invalid(look)) {
|
||||
/* Reject */
|
||||
return fallback;
|
||||
}
|
||||
return (CONST char *)look;
|
||||
}
|
||||
|
||||
/* We saw a trail byte. */
|
||||
trailBytesSeen++;
|
||||
|
||||
if ((CONST char *)look == start) {
|
||||
/*
|
||||
* Do not read before the start of the string
|
||||
*
|
||||
* If we get here, we've examined bytes at every location
|
||||
* >= start and < src and all of them are trail bytes,
|
||||
* including (*start). We need to return our fallback
|
||||
* and exit this loop before we run past the start of the string.
|
||||
*/
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/* Continue the search backwards... */
|
||||
look--;
|
||||
}
|
||||
return src;
|
||||
} while (trailBytesSeen < TCL_UTF_MAX);
|
||||
|
||||
/*
|
||||
* We've seen TCL_UTF_MAX trail bytes, so we know there will not be a
|
||||
* properly formed byte sequence to find, and we can stop looking,
|
||||
* accepting the fallback.
|
||||
*/
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+731
-113
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user