Difference between revisions of "BaseN"

From Second Life Wiki
Jump to navigation Jump to search
(Created page with '{{LSL Header}} __Toc__ This script allows you to make maximum use of available bits in strings for transport or storage in memory. By being able to code integers into the usable...')
 
(Added upgraded list-based version)
Line 6: Line 6:
Note that this script does not code to the same standards such as Base64, but instead maps dynamically to the ''usable code points'' as allowed by Linden Lab.
Note that this script does not code to the same standards such as Base64, but instead maps dynamically to the ''usable code points'' as allowed by Linden Lab.


{{box|Header|
{{box|Portable List-based Coding|
<lsl>
<lsl>
/*/
/*/
Line 13: Line 13:
     unless otherwise noted
     unless otherwise noted
/*/
/*/
integer UTF8ToInt(string input) {// by Strife
    integer result = llBase64ToInteger(llStringToBase64(input));//input = llGetSubString(input,0,0)));
    if(result & 0x80000000){
        integer end = (integer)("0x"+llGetSubString(input = (string)llParseString2List(llEscapeURL(input),(list)"%",[]),-8,-1));
        integer begin = (integer)("0x"+llDeleteSubString(input,-8,-1));
        return  (  (  0x0000003f &  end        ) | (( 0x00003f00 &  end) >> 2  ) |
                    (( 0x003f0000 &  end) >> 4  ) | (( 0x3f000000 &  end) >> 6  ) |
                    (( 0x0000003f &  begin) << 24) | (( 0x00000100 &  begin) << 22) ) &
                    (0x7FFFFFFF >> (5 * ((integer)(llLog(~result) / 0.69314718055994530941723212145818) - 25)));
    } return result >> 24; }
string IntToUTF8(integer input) {// by Strife
    integer bytes = llCeil(llLog(input) / 0.69314718055994530941723212145818);
    bytes = (input >= 0x80) * (bytes + ~(((1 << bytes) - input) > 0)) / 5;
    string result = "%" + byte2hex((input >> (6 * bytes)) | ((0x3F80 >> bytes) << !bytes));
    while (bytes) result += "%" + byte2hex((((input >> (6 * (bytes = ~-bytes))) | 0x80) & 0xBF));
    return llUnescapeURL(result); }
string byte2hex(integer x) { integer y = (x >> 4) & 0xF;// By Strife
    return llGetSubString(Hex, y, y) + llGetSubString(Hex, x & 0xF, x & 0xF); }
string Hex = "0123456789abcdef";
key Ints2Key( integer a, integer b, integer c, integer d ) {
    return byte2hex(a>>24)+byte2hex(a>>16)+byte2hex(a>>8)+byte2hex(a)+"-"+
          byte2hex(b>>24)+byte2hex(b>>16)+"-"+byte2hex(b>>8)+byte2hex(b)+"-"+
          byte2hex(c>>24)+byte2hex(c>>16)+"-"+byte2hex(c>>8)+byte2hex(c)+
          byte2hex(d>>24)+byte2hex(d>>16)+byte2hex(d>>8)+byte2hex(d); }
integer fui(float input){// by Strife
    if((input) != 0.0){
        integer sign = (input < 0) << 31;
        if((input = llFabs(input)) < 2.3509887016445750159374730744445e-38)
            return sign | (integer)(input / 1.4012984643248170709237295832899e-45);
        integer exp = llFloor((llLog(input) / 0.69314718055994530941723212145818));
        return (0x7FFFFF & (integer)(input * (0x1000000 >> sign))) | (((exp + 126 + (sign = ((integer)input - (3 <= (input /= (float)("0x1p"+(string)(exp -= ((exp >> 31) | 1)))))))) << 23 ) | sign);
    } return ((string)input == (string)(-0.0)) << 31; }
float iuf(integer input){// by Strife
    return llPow(2.0, (input | !input) - 150) * (((!!(input = (0xff & (input >> 23)))) << 23) | ((input & 0x7fffff))) * (1 | (input >> 31)); }
list Unusable = [0x00,1, 0x0D,1, /*|*/0x7C,1, /*~*/0x7E,1, 0xD800,2047, 0xFDD0,31, 0xFFFE,2];
    // Unusable: 0000, 000D, D800-DFFF, FDD0-FDEF, FFFE and FFFF.
    //              0(1), 13(1), 124(1), 126(1), 55296(2047), 64976(31), 65534(2),
    // Reserved for delimiters: '~' and '|'.
    // 1-byte: Base123, 2-byte: Base2043, 3-byte: Base1112025
string IntToBaseToUTF8( integer Int, integer Base ) {
    // Integer to Base
    integer Sign = (Int < 0); if(Sign) Int = -Int;
    integer M = Int%(Base/2);
    list Coded = [M + (Base/2)*Sign];
    Int = Int / (Base/2);
    while( Int > Base ) { Coded = [Int%Base] + Coded; Int /= Base; }
    if(Int) Coded = [Int] + Coded;
   
    // Base to UTF8
    integer a; integer b = llGetListLength(Coded); list lEnc;
    for( ; a < b; ++a ) {
        Int = llList2Integer(Coded,a);
        integer c; integer d = llGetListLength(Unusable);
        for(; c < d; c += 2 ) {
            if( Int >= llList2Integer(Unusable,c) )
                Int += llList2Integer(Unusable,c+1);
            else c = d;
        } lEnc += IntToUTF8(Int);
    }
    if(Base > 60000) return llDumpList2String(lEnc,"|");
                else return (string)lEnc;
}
integer UTF8ToBaseToInt( string UTF8, integer Base ) {
    // UTF8 to Base
    list lDec;
    if(Base > 60000) lDec = llParseString2List(UTF8,["|"],[]);
    else { integer h = llStringLength(UTF8);
          while(h--) lDec = llGetSubString(UTF8,h,h) + lDec; }
   
    integer i; integer j = llGetListLength(lDec); list Coded;
    for(; i < j; ++i ) {
        string Char = llList2String(lDec,i);
        integer Int = UTF8ToInt(Char); integer l = llGetListLength(Unusable)-1;
        for(; l > 0; l -= 2 ) {
            if( Int >= llList2Integer(Unusable,l-1) )
                Int -= llList2Integer(Unusable,l);
        } Coded += [Int];
    }
   
    // Base to Integer
    integer Int; integer k = llGetListLength(Coded); integer Exp = Base/2; integer Sign;
    Int = llList2Integer(Coded,--k);
    if( Int > Exp ) { Sign = 1; Int -= Exp; }
    while( k-- ){ Int += llList2Integer(Coded,k) * Exp; Exp *= Base; }
    if(Sign) Int = -Int;
    return Int;
}
string Compress( integer Bytes, list Input ) {
    integer Base;
    if(Bytes == 1) Base = 123; else
    if(Bytes == 2) Base = 2043; else
    if(Bytes == 3) Base = 1112025;
    list Types; list Compressed; integer x; integer y = llGetListLength(Input);
    for( ; x < y; ++x ) {
       
        // Get as Integer(s) from List Entry, and compress
        integer Type = llGetListEntryType(Input,x);
        if(Type == TYPE_INTEGER) {
            integer Int0 = llList2Integer(Input,x);
            Compressed += [IntToBaseToUTF8(Int0,Base)];
        } else if(Type == TYPE_FLOAT) {
            integer Int0 = fui(llList2Float(Input,x));
            Compressed += [IntToBaseToUTF8(Int0,Base)];
        } else if(Type == TYPE_KEY) {
            string s = llDumpList2String(llParseString2List(llList2String(Input,x), ["-"], []), "");
            integer Int0 = (integer)("0x"+llGetSubString(s,0,7));
            integer Int1 = (integer)("0x"+llGetSubString(s,8,15));
            integer Int2 = (integer)("0x"+llGetSubString(s,16,23));
            integer Int3 = (integer)("0x"+llGetSubString(s,24,31));
            Compressed += [IntToBaseToUTF8(Int0,Base),
                          IntToBaseToUTF8(Int1,Base),
                          IntToBaseToUTF8(Int2,Base),
                          IntToBaseToUTF8(Int3,Base)];
        } else if(Type == TYPE_VECTOR) {
            vector v = llList2Vector(Input,x);
            integer Int0 = fui(v.x);
            integer Int1 = fui(v.y);
            integer Int2 = fui(v.z);
            Compressed += [IntToBaseToUTF8(Int0,Base),
                          IntToBaseToUTF8(Int1,Base),
                          IntToBaseToUTF8(Int2,Base)];
        } else if(Type == TYPE_ROTATION) {
            rotation v = llList2Rot(Input,x);
            integer Int0 = fui(v.x);
            integer Int1 = fui(v.y);
            integer Int2 = fui(v.z);
            integer Int3 = fui(v.s);
            Compressed += [IntToBaseToUTF8(Int0,Base),
                          IntToBaseToUTF8(Int1,Base),
                          IntToBaseToUTF8(Int2,Base),
                          IntToBaseToUTF8(Int3,Base)];
        } else if(Type == TYPE_STRING) {
            Compressed += llList2String(Input,x);
        }
       
        // Add to header
        integer Row = x%10;
        if(!Row) Types += Type; else {
            integer Col = x/10;
            integer t = llList2Integer( Types, Col );
            t = t | (Type<<(Row*3));
            Types = llListReplaceList( Types, [t], Col, Col );
    }  }
    // Compress header
    y = llGetListLength((Types = y + Types));
    for( x = 0; x < y; ++x )
        Types = llListReplaceList( Types, [IntToBaseToUTF8(llList2Integer(Types,x),Base)], x, x );
   
    return llDumpList2String(Types + Compressed,"~"); }
list Decompress( integer Bytes, string Encrypted ) {
    integer Base;
    if(Bytes == 1) Base = 123; else
    if(Bytes == 2) Base = 2043; else
    if(Bytes == 3) Base = 1112025;
    list Input = llParseString2List(Encrypted,["~"],[]);
   
    integer Total = UTF8ToBaseToInt( llList2String(Input,0), Base );
    integer x; integer y; list Types;
    for( y = 1+(Total/10); x < y; ++x )
        Types += UTF8ToBaseToInt( llList2String(Input,x+1), Base );
   
    list Output; integer Ptr = y;
    for( x = 0; x < Total; ++x ) {
        integer Row = x%10;
        integer Col = x/10;
        integer Type = (llList2Integer(Types,Col)>>(Row*3))&7;
       
        if(Type == TYPE_INTEGER) {
            Output += [UTF8ToBaseToInt(llList2String(Input,Ptr++),Base)];
        } else if(Type == TYPE_FLOAT) {
            Output += [iuf(UTF8ToBaseToInt(llList2String(Input,Ptr++),Base))];
        } else if(Type == TYPE_KEY) {
            integer Int0 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int1 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int2 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int3 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            Output += [Ints2Key(Int0,Int1,Int2,Int3)];
        } else if(Type == TYPE_VECTOR) {
            integer Int0 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int1 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int2 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            Output += [<iuf(Int0),iuf(Int1),iuf(Int2)>];
        } else if(Type == TYPE_ROTATION) {
            integer Int0 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int1 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int2 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            integer Int3 = UTF8ToBaseToInt(llList2String(Input,Ptr++),Base);
            Output += [<iuf(Int0),iuf(Int1),iuf(Int2),iuf(Int3)>];
        } else if(Type == TYPE_STRING) {
            Output += [llList2String(Input,Ptr++)];
        }
    }
    return Output;
}
integer UTF8Length(string msg) {// by kimmie Loveless
    integer rNum = llStringLength(msg); return rNum + ((llStringLength(llEscapeURL(msg)) - rNum)/4); }
default {
    state_entry() {
        string HR = "------";
        list In = [ 25.6, 29555, 655960, -90005, 65.0125, <6, 6, 6>, <7, 7, 7, 7>,
            (key)"75078730-ebc8-4a80-adb9-1cfd2d95b5ca", 9, 10., 1, <2.,0,0>, 3, 4., 5,
            <6.,0,0,0>, 7, <8.,0,0>, 9, 1564.756560 ];
        list Counts = [10,    10,      10,      10,      10,        18,            22,
                                                      54, 10,  10, 10,        18, 10,  10, 10,
                    22, 10,        18, 10,  10 ];
        llOwnerSay((string)[HR," Elements: ",llGetListLength(Counts),
            " (",(integer)llListStatistics(LIST_STAT_SUM,Counts)," bytes) ",HR]);
       
        llOwnerSay(HR+" Compress "+HR);
        string Enc = Compress( 1, In );
       
        llOwnerSay(HR+" Decompress "+HR);
        list Dec = Decompress( 1, Enc );
       
        string dIn = llDumpList2String(In,",");
        string dDec = llDumpList2String(Dec,",");
       
        llOwnerSay( (string)[HR," Debug ",HR,
            "\n",HR," Input ",HR,"\n",dIn,
            "\n",HR," Encrypted (",UTF8Length(Enc)," bytes) ",HR,"\n",Enc,
            "\n",HR," Output ",HR,"\n",dDec] );
    }
}
</lsl>
</lsl>
}}
}}


{{box|Main Functions|
 
 
{{box|Single Integer Coding|
<lsl>
<lsl>
/*/
        Variable Base
    created by Nexii
    unless otherwise noted
/*/
list Int2Base( integer Base, integer Int ) {
list Int2Base( integer Base, integer Int ) {
     integer Sign = (Int < 0); if(Sign) Int = -Int;
     integer Sign = (Int < 0); if(Sign) Int = -Int;
Line 50: Line 297:
             Int -= llList2Integer(Unusable,y);
             Int -= llList2Integer(Unusable,y);
     } return Int; }
     } return Int; }
</lsl>
}}


{{box|Required Helper Functions|
 
<lsl>
integer UTF8ToInt(string input) {// by Strife
integer UTF8ToInt(string input) {// by Strife
     integer result = llBase64ToInteger(llStringToBase64(input = llGetSubString(input,0,0)));
     integer result = llBase64ToInteger(llStringToBase64(input = llGetSubString(input,0,0)));
Line 74: Line 318:
     return llGetSubString(Hex, y, y) + llGetSubString(Hex, x & 0xF, x & 0xF); }
     return llGetSubString(Hex, y, y) + llGetSubString(Hex, x & 0xF, x & 0xF); }
string Hex = "0123456789ABCDEF";
string Hex = "0123456789ABCDEF";
</lsl>
}}


{{box|Test Script|
 
<lsl>
integer UTF8Length(string msg) {// by kimmie Loveless
integer UTF8Length(string msg) {// by kimmie Loveless
     integer rNum = llStringLength(msg); return rNum + ((llStringLength(llEscapeURL(msg)) - rNum)/4); }
     integer rNum = llStringLength(msg); return rNum + ((llStringLength(llEscapeURL(msg)) - rNum)/4); }
Line 130: Line 371:
</lsl>
</lsl>
}}
}}
{{LSLC|Library}}
{{LSLC|Library}}

Revision as of 14:18, 5 August 2010

This script allows you to make maximum use of available bits in strings for transport or storage in memory. By being able to code integers into the usable space of UTF-8 and UTF-16.

Note that this script does not code to the same standards such as Base64, but instead maps dynamically to the usable code points as allowed by Linden Lab.

Portable List-based Coding

(( 0x00003f00 &  end) >> 2   ) 



Single Integer Coding

(( 0x00003f00 &  end) >> 2   )