diff --git a/builtins.txt b/builtins.txt index c33168e..289e97d 100644 --- a/builtins.txt +++ b/builtins.txt @@ -24,6 +24,7 @@ void llBreakLink( integer linknum ) list llCSV2List( string src ) list llCastRay( vector start, vector end, list params ) integer llCeil( float val ) +string llChar( integer code ) void llClearCameraParams( ) void llClearExperiencePermissions( key agent ) integer llClearLinkMedia( integer link, integer face ) @@ -214,6 +215,7 @@ void llGroundRepel( float height, integer water, float tau ) vector llGroundSlope( vector offset ) key llHTTPRequest( string url, list parameters, string body ) void llHTTPResponse( key request_id, integer status, string body ) +integer llHash( string val ) string llInsertString( string dst, integer position, string src ) void llInstantMessage( key user, string message ) string llIntegerToBase64( integer number ) @@ -269,6 +271,7 @@ key llName2Key( string name ) void llNavigateTo( vector point, list options ) void llOffsetTexture( float u, float v, integer face ) void llOpenRemoteDataChannel( ) +integer llOrd( string val, integer index ) integer llOverMyLand( key id ) void llOwnerSay( string msg ) void llParcelMediaCommandList( list command ) diff --git a/fndata.txt b/fndata.txt index a7d642a..6f8f973 100644 --- a/fndata.txt +++ b/fndata.txt @@ -1578,7 +1578,7 @@ string llXorBase64StringsCorrect(string str1, string str2) integer llReplaceAgentEnvironment(key agent_id, float transition, string environment) - unstable -integer llSetAgentEnvironment( key agent_id, float transition, list params ) +integer llSetAgentEnvironment(key agent_id, float transition, list params) - unstable float llGetRegionTimeOfDay() @@ -1587,6 +1587,15 @@ float llGetRegionTimeOfDay() - min 0 - max 86399.9921875 +string llChar(integer code) +- SEF + +integer llHash(string val) +- SEF + +integer llOrd(string val, integer index) +- SEF + ################################################################### # Events are SEF if a script with an empty event can't be diff --git a/lslopt/lslbasefuncs.py b/lslopt/lslbasefuncs.py index 4f38519..a15767b 100644 --- a/lslopt/lslbasefuncs.py +++ b/lslopt/lslbasefuncs.py @@ -1098,6 +1098,54 @@ def llCeil(f): return -2147483648 return int(math.ceil(f)) +def llChar(code): + code = fi(code) + # The result is consistent with a conversion of the codepoint to + # UTF-8-1993, then using InternalUTF8toString on the result. + # A thorough test shows that llChar(n) equals llUnescapeURL(utf8_1993) + # up to codepoint 0x13FFFF. Furthermore llChar(0x200000) returns "?????", + # and llChar(0x7FFFFFFF) returns "??????", which are also consistent with + # that. LSO also returns UTF-8-1993 for codepoints > 0x10FFFF. So, the + # internal implementation is likely to form a UTF8-1993 string from the + # codepoint and then convert that to string, like this: +# if code < 0: +# return u'?' +# if code < 0x80: +# s = (code,) +# elif code < 0x800: +# s = (0xC0+(code >> 6), 0x80+(code&0x3F)) +# elif code < 0x10000: +# s = (0xE0+(code >> 12), 0x80+((code >> 6)&0x3F), 0x80+(code&0x3F)) +# elif code < 0x200000: +# s = (0xF0+(code >> 18), 0x80+((code >> 12)&0x3F), +# 0x80+((code >> 6)&0x3F), 0x80+(code&0x3F)) +# elif code < 0x4000000: +# s = (0xF8+(code >> 24), +# 0x80+((code >> 18)&0x3F), 0x80+((code >> 12)&0x3F), +# 0x80+((code >> 6)&0x3F), 0x80+(code&0x3F)) +# else: +# s = (0xFC+(code >> 30), 0x80+((code >> 24)&0x3F), +# 0x80+((code >> 18)&0x3F), 0x80+((code >> 12)&0x3F), +# 0x80+((code >> 6)&0x3F), 0x80+(code&0x3F)) +# return zstr(InternalUTF8toString(bytearray(s))) + + # Here's an alternative, simpler implementation that only works for Mono: + if lslcommon.LSO: + raise ELSLCantCompute + if code == 0: + return u'' + if code < 0: + return u'?' + if code > 0x10FFFF: + if code >= 0x4000000: + return u'??????' + if code >= 0x200000: + return u'?????' + return u'????' + if (0xD800 <= code <= 0xDFFF) or code == 0xFFFE: + return u'???' + return unichr(code) + def llCos(f): f = ff(f) if math.isinf(f): @@ -1235,6 +1283,13 @@ def llGetSubString(s, start, end): s = fs(s) return InternalGetDeleteSubSequence(s, start, end, isGet=True) +def llHash(s): + s = fs(s) + hash = 0 + for i in s: + hash = (hash * 65599 + ord(i)) & 0xFFFFFFFF + return S32(hash) + def llInsertString(s, pos, src): s = fs(s) pos = fi(pos) @@ -1625,6 +1680,14 @@ def llModPow(base, exp, mod): return S32(ret) +def llOrd(val, index): + val = fs(val) + index = fi(index) + L = len(val) + if -L <= index < L: + return ord(val[index]) # we're assuming it won't ever need F32() + return 0 + def llParseString2List(s, exc, inc, KeepNulls=False): s = fs(s) exc = fl(exc) diff --git a/unit_tests/expr.suite/llord-char-hash.lsl b/unit_tests/expr.suite/llord-char-hash.lsl new file mode 100644 index 0000000..1a8a3dc --- /dev/null +++ b/unit_tests/expr.suite/llord-char-hash.lsl @@ -0,0 +1,35 @@ +[ llOrd("", 0) +, llOrd(".", -2) +, llOrd(".", -1) +, llOrd(".", 0) +, llOrd(".", 1) +, llOrd(".", 2) +, llOrd("ð", 0) +, llOrd("𝄞𝐀", 0) +, llOrd("𝄞𝐀", 1) +, llOrd("𝄞𝐀", 2) +, llOrd("𝄞𝐀", 3) +, llOrd(JSON_TRUE, 0) +, llOrd(llUnescapeURL("%EF%BF%BF"), 0) +, llEscapeURL(llChar(-123)) +, llEscapeURL(llChar(-1)) +, llEscapeURL(llChar(0)) +, llEscapeURL(llChar(1)) +, llEscapeURL(llChar(0xA9)) +, llEscapeURL(llChar(0x14D)) +, llEscapeURL(llChar(0x2010)) +, llEscapeURL(llChar(0xD800)) +, llEscapeURL(llChar(0xDB00)) +, llEscapeURL(llChar(0xFFFE)) +, llEscapeURL(llChar(0xFFFF)) +, llEscapeURL(llChar(0x1F600)) +, llEscapeURL(llChar(0x10FFFF)) +, llEscapeURL(llChar(0x110000)) +, llEscapeURL(llChar(0x200000)) +, llEscapeURL(llChar(0x4000000)) +, llEscapeURL(llChar(0x7F000000)) +, llEscapeURL(llChar(0x80000000)) +, llHash("ð𝄞𝐀") +, llHash("") +, llHash("𝐀𝄞ð") +] diff --git a/unit_tests/expr.suite/llord-char-hash.out b/unit_tests/expr.suite/llord-char-hash.out new file mode 100644 index 0000000..c33b750 --- /dev/null +++ b/unit_tests/expr.suite/llord-char-hash.out @@ -0,0 +1,35 @@ +[ 0 +, 0 +, 46 +, 46 +, 0 +, 0 +, 240 +, 119070 +, 119808 +, 0 +, 0 +, 64982 +, 65535 +, "%3F" +, "%3F" +, "" +, "%01" +, "%C2%A9" +, "%C5%8D" +, "%E2%80%90" +, "%3F%3F%3F" +, "%3F%3F%3F" +, "%3F%3F%3F" +, "%EF%BF%BF" +, "%F0%9F%98%80" +, "%F4%8F%BF%BF" +, "%3F%3F%3F%3F" +, "%3F%3F%3F%3F%3F" +, "%3F%3F%3F%3F%3F%3F" +, "%3F%3F%3F%3F%3F%3F" +, "%3F" +, 1203819346 +, 0 +, 1172851538 +] \ No newline at end of file