diff options
author | George Hazan <ghazan@miranda.im> | 2020-07-02 19:37:06 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2020-07-02 19:37:06 +0300 |
commit | d35fd87e643656a43e1ec19e18ead85839886679 (patch) | |
tree | d3c67be211c7e5ff89d339710ab65b82be9ce99f /libs/liblua/src/lutf8lib.c | |
parent | f10699e580b3eead1cb9c250822abbbc626eb3e3 (diff) |
fixes #2472 (Update liblua to 5.4)
Diffstat (limited to 'libs/liblua/src/lutf8lib.c')
-rw-r--r-- | libs/liblua/src/lutf8lib.c | 117 |
1 files changed, 75 insertions, 42 deletions
diff --git a/libs/liblua/src/lutf8lib.c b/libs/liblua/src/lutf8lib.c index 10bd238a71..901d985f8d 100644 --- a/libs/liblua/src/lutf8lib.c +++ b/libs/liblua/src/lutf8lib.c @@ -1,5 +1,5 @@ /* -** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ +** $Id: lutf8lib.c $ ** Standard library for UTF-8 manipulation ** See Copyright Notice in lua.h */ @@ -20,7 +20,20 @@ #include "lauxlib.h" #include "lualib.h" -#define MAXUNICODE 0x10FFFF + +#define MAXUNICODE 0x10FFFFu + +#define MAXUTF 0x7FFFFFFFu + +/* +** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits. +*/ +#if (UINT_MAX >> 30) >= 1 +typedef unsigned int utfint; +#else +typedef unsigned long utfint; +#endif + #define iscont(p) ((*(p) & 0xC0) == 0x80) @@ -35,53 +48,62 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) { /* -** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. +** Decode one UTF-8 sequence, returning NULL if byte sequence is +** invalid. The array 'limits' stores the minimum value for each +** sequence length, to check for overlong representations. Its first +** entry forces an error for non-ascii bytes with no continuation +** bytes (count == 0). */ -static const char *utf8_decode (const char *o, int *val) { - static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; - const unsigned char *s = (const unsigned char *)o; - unsigned int c = s[0]; - unsigned int res = 0; /* final result */ +static const char *utf8_decode (const char *s, utfint *val, int strict) { + static const utfint limits[] = + {~(utfint)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u}; + unsigned int c = (unsigned char)s[0]; + utfint res = 0; /* final result */ if (c < 0x80) /* ascii? */ res = c; else { int count = 0; /* to count number of continuation bytes */ - while (c & 0x40) { /* still have continuation bytes? */ - int cc = s[++count]; /* read next byte */ + for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ + unsigned int cc = (unsigned char)s[++count]; /* read next byte */ if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ return NULL; /* invalid byte sequence */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ - c <<= 1; /* to test next bit */ } - res |= ((c & 0x7F) << (count * 5)); /* add first byte */ - if (count > 3 || res > MAXUNICODE || res <= limits[count]) + res |= ((utfint)(c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 5 || res > MAXUTF || res < limits[count]) return NULL; /* invalid byte sequence */ s += count; /* skip continuation bytes read */ } + if (strict) { + /* check for invalid code points; too large or surrogates */ + if (res > MAXUNICODE || (0xD800u <= res && res <= 0xDFFFu)) + return NULL; + } if (val) *val = res; - return (const char *)s + 1; /* +1 to include first byte */ + return s + 1; /* +1 to include first byte */ } /* -** utf8len(s [, i [, j]]) --> number of characters that start in the -** range [i,j], or nil + current position if 's' is not well formed in -** that interval +** utf8len(s [, i [, j [, lax]]]) --> number of characters that +** start in the range [i,j], or nil + current position if 's' is not +** well formed in that interval */ static int utflen (lua_State *L) { - int n = 0; - size_t len; + lua_Integer n = 0; /* counter for the number of characters */ + size_t len; /* string length in bytes */ const char *s = luaL_checklstring(L, 1, &len); lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + int lax = lua_toboolean(L, 4); luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, - "initial position out of string"); + "initial position out of bounds"); luaL_argcheck(L, --posj < (lua_Integer)len, 3, - "final position out of string"); + "final position out of bounds"); while (posi <= posj) { - const char *s1 = utf8_decode(s + posi, NULL); + const char *s1 = utf8_decode(s + posi, NULL, !lax); if (s1 == NULL) { /* conversion error? */ - lua_pushnil(L); /* return nil ... */ + luaL_pushfail(L); /* return fail ... */ lua_pushinteger(L, posi + 1); /* ... and current position */ return 2; } @@ -94,28 +116,29 @@ static int utflen (lua_State *L) { /* -** codepoint(s, [i, [j]]) -> returns codepoints for all characters -** that start in the range [i,j] +** codepoint(s, [i, [j [, lax]]]) -> returns codepoints for all +** characters that start in the range [i,j] */ static int codepoint (lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int lax = lua_toboolean(L, 4); int n; const char *se; - luaL_argcheck(L, posi >= 1, 2, "out of range"); - luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); + luaL_argcheck(L, posi >= 1, 2, "out of bounds"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of bounds"); if (posi > pose) return 0; /* empty interval; return no values */ if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ return luaL_error(L, "string slice too long"); - n = (int)(pose - posi) + 1; + n = (int)(pose - posi) + 1; /* upper bound for number of returns */ luaL_checkstack(L, n, "string slice too long"); - n = 0; - se = s + pose; + n = 0; /* count the number of returns */ + se = s + pose; /* string end */ for (s += posi - 1; s < se;) { - int code; - s = utf8_decode(s, &code); + utfint code; + s = utf8_decode(s, &code, !lax); if (s == NULL) return luaL_error(L, "invalid UTF-8 code"); lua_pushinteger(L, code); @@ -126,8 +149,8 @@ static int codepoint (lua_State *L) { static void pushutfchar (lua_State *L, int arg) { - lua_Integer code = luaL_checkinteger(L, arg); - luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); + lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg); + luaL_argcheck(L, code <= MAXUTF, arg, "value out of range"); lua_pushfstring(L, "%U", (long)code); } @@ -164,7 +187,7 @@ static int byteoffset (lua_State *L) { lua_Integer posi = (n >= 0) ? 1 : len + 1; posi = u_posrelat(luaL_optinteger(L, 3, posi), len); luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, - "position out of range"); + "position out of bounds"); if (n == 0) { /* find beginning of current byte sequence */ while (posi > 0 && iscont(s + posi)) posi--; @@ -193,12 +216,12 @@ static int byteoffset (lua_State *L) { if (n == 0) /* did it find given character? */ lua_pushinteger(L, posi + 1); else /* no such character */ - lua_pushnil(L); + luaL_pushfail(L); return 1; } -static int iter_aux (lua_State *L) { +static int iter_aux (lua_State *L, int strict) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer n = lua_tointeger(L, 2) - 1; @@ -211,9 +234,9 @@ static int iter_aux (lua_State *L) { if (n >= (lua_Integer)len) return 0; /* no more codepoints */ else { - int code; - const char *next = utf8_decode(s + n, &code); - if (next == NULL || iscont(next)) + utfint code; + const char *next = utf8_decode(s + n, &code, strict); + if (next == NULL) return luaL_error(L, "invalid UTF-8 code"); lua_pushinteger(L, n + 1); lua_pushinteger(L, code); @@ -222,9 +245,19 @@ static int iter_aux (lua_State *L) { } +static int iter_auxstrict (lua_State *L) { + return iter_aux(L, 1); +} + +static int iter_auxlax (lua_State *L) { + return iter_aux(L, 0); +} + + static int iter_codes (lua_State *L) { + int lax = lua_toboolean(L, 2); luaL_checkstring(L, 1); - lua_pushcfunction(L, iter_aux); + lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict); lua_pushvalue(L, 1); lua_pushinteger(L, 0); return 3; @@ -232,7 +265,7 @@ static int iter_codes (lua_State *L) { /* pattern to match a single UTF-8 character */ -#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" +#define UTF8PATT "[\0-\x7F\xC2-\xFD][\x80-\xBF]*" static const luaL_Reg funcs[] = { |