aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorSean Dague2008-02-28 21:25:28 +0000
committerSean Dague2008-02-28 21:25:28 +0000
commitde1024adf71b05c9f2f4f89fbda891211de03a42 (patch)
treef6bb06b8272b26e11cb92d20b3631fdaa8a2e4de
parentsample change to see if rev actually changes on prebuild when I do this (diff)
downloadopensim-SC-de1024adf71b05c9f2f4f89fbda891211de03a42.zip
opensim-SC-de1024adf71b05c9f2f4f89fbda891211de03a42.tar.gz
opensim-SC-de1024adf71b05c9f2f4f89fbda891211de03a42.tar.bz2
opensim-SC-de1024adf71b05c9f2f4f89fbda891211de03a42.tar.xz
From: Alan M Webb <awebb@vnet.ibm.com>
This patch is intended to implement the following functions: llIntegerToBase64 llBase64ToInteger llParseStringKeepNulls None of these functions are dependent upon state elsewhere in the SIM, so they are appropriately self-contained. I've tested them out of context, and from a script attached to an object in my test region.
-rw-r--r--OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs427
1 files changed, 418 insertions, 9 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs
index 7d4219b..7b59d73 100644
--- a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs
+++ b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs
@@ -3244,18 +3244,259 @@ namespace OpenSim.Region.ScriptEngine.Common
3244 NotImplemented("llGetPrimitiveParams"); 3244 NotImplemented("llGetPrimitiveParams");
3245 } 3245 }
3246 3246
3247 // <remarks>
3248 // <para>
3249 // The .NET definition of base 64 is:
3250 // <list>
3251 // <item>
3252 // Significant: A-Z a-z 0-9 + -
3253 // </item>
3254 // <item>
3255 // Whitespace: \t \n \r ' '
3256 // </item>
3257 // <item>
3258 // Valueless: =
3259 // </item>
3260 // <item>
3261 // End-of-string: \0 or '=='
3262 // </item>
3263 // </list>
3264 // </para>
3265 // <para>
3266 // Each point in a base-64 string represents
3267 // a 6 bit value. A 32-bit integer can be
3268 // represented using 6 characters (with some
3269 // redundancy).
3270 // </para>
3271 // <para>
3272 // LSL requires a base64 string to be 8
3273 // characters in length. LSL also uses '/'
3274 // rather than '-' (MIME compliant).
3275 // </para>
3276 // <para>
3277 // RFC 1341 used as a reference (as specified
3278 // by the SecondLife Wiki).
3279 // </para>
3280 // <para>
3281 // SL do not record any kind of exception for
3282 // these functions, so the string to integer
3283 // conversion returns '0' if an invalid
3284 // character is encountered during conversion.
3285 // </para>
3286 // <para>
3287 // References
3288 // <list>
3289 // <item>
3290 // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
3291 // </item>
3292 // <item>
3293 // </item>
3294 // </list>
3295 // </para>
3296 // </remarks>
3297
3298 // <summary>
3299 // Table for converting 6-bit integers into
3300 // base-64 characters
3301 // </summary>
3302
3303 private static readonly char[] i2ctable =
3304 {
3305 'A','B','C','D','E','F','G','H',
3306 'I','J','K','L','M','N','O','P',
3307 'Q','R','S','T','U','V','W','X',
3308 'Y','Z',
3309 'a','b','c','d','e','f','g','h',
3310 'i','j','k','l','m','n','o','p',
3311 'q','r','s','t','u','v','w','x',
3312 'y','z',
3313 '0','1','2','3','4','5','6','7',
3314 '8','9',
3315 '+','/'
3316 };
3317
3318 // <summary>
3319 // Table for converting base-64 characters
3320 // into 6-bit integers.
3321 // </summary>
3322
3323 private static readonly int[] c2itable =
3324 {
3325 -1,-1,-1,-1,-1,-1,-1,-1, // 0x
3326 -1,-1,-1,-1,-1,-1,-1,-1,
3327 -1,-1,-1,-1,-1,-1,-1,-1, // 1x
3328 -1,-1,-1,-1,-1,-1,-1,-1,
3329 -1,-1,-1,-1,-1,-1,-1,-1, // 2x
3330 -1,-1,-1,63,-1,-1,-1,64,
3331 53,54,55,56,57,58,59,60, // 3x
3332 61,62,-1,-1,-1,0,-1,-1,
3333 -1,1,2,3,4,5,6,7, // 4x
3334 8,9,10,11,12,13,14,15,
3335 16,17,18,19,20,21,22,23, // 5x
3336 24,25,26,-1,-1,-1,-1,-1,
3337 -1,27,28,29,30,31,32,33, // 6x
3338 34,35,36,37,38,39,40,41,
3339 42,43,44,45,46,47,48,49, // 7x
3340 50,51,52,-1,-1,-1,-1,-1,
3341 -1,-1,-1,-1,-1,-1,-1,-1, // 8x
3342 -1,-1,-1,-1,-1,-1,-1,-1,
3343 -1,-1,-1,-1,-1,-1,-1,-1, // 9x
3344 -1,-1,-1,-1,-1,-1,-1,-1,
3345 -1,-1,-1,-1,-1,-1,-1,-1, // Ax
3346 -1,-1,-1,-1,-1,-1,-1,-1,
3347 -1,-1,-1,-1,-1,-1,-1,-1, // Bx
3348 -1,-1,-1,-1,-1,-1,-1,-1,
3349 -1,-1,-1,-1,-1,-1,-1,-1, // Cx
3350 -1,-1,-1,-1,-1,-1,-1,-1,
3351 -1,-1,-1,-1,-1,-1,-1,-1, // Dx
3352 -1,-1,-1,-1,-1,-1,-1,-1,
3353 -1,-1,-1,-1,-1,-1,-1,-1, // Ex
3354 -1,-1,-1,-1,-1,-1,-1,-1,
3355 -1,-1,-1,-1,-1,-1,-1,-1, // Fx
3356 -1,-1,-1,-1,-1,-1,-1,-1
3357 };
3358
3359 // <summary>
3360 // Converts a 32-bit integer into a Base64
3361 // character string. Base64 character strings
3362 // are always 8 characters long. All iinteger
3363 // values are acceptable.
3364 // </summary>
3365 // <param name="number">
3366 // 32-bit integer to be converted.
3367 // </param>
3368 // <returns>
3369 // 8 character string. The 1st six characters
3370 // contain the encoded number, the last two
3371 // characters are padded with "=".
3372 // </returns>
3373
3247 public string llIntegerToBase64(int number) 3374 public string llIntegerToBase64(int number)
3248 { 3375 {
3249 m_host.AddScriptLPS(1); 3376
3250 NotImplemented("llIntegerToBase64"); 3377 // uninitialized string
3251 return String.Empty; 3378
3252 } 3379 char[] imdt = new char[8];
3380
3381 m_host.AddScriptLPS(1);
3382
3383 // Manually unroll the loop
3384
3385 imdt[7] = '=';
3386 imdt[6] = '=';
3387 imdt[5] = i2ctable[number<<4 & 0x3F];
3388 imdt[4] = i2ctable[number>>2 & 0x3F];
3389 imdt[3] = i2ctable[number>>8 & 0x3F];
3390 imdt[2] = i2ctable[number>>14 & 0x3F];
3391 imdt[1] = i2ctable[number>>20 & 0x3F];
3392 imdt[0] = i2ctable[number>>26 & 0x3F];
3393
3394 return new string(imdt);
3395
3396 }
3397
3398 // <summary>
3399 // Converts an eight character base-64 string
3400 // into a 32-bit integer.
3401 // </summary>
3402 // <param name="str">
3403 // 8 characters string to be converted. Other
3404 // length strings return zero.
3405 // </param>
3406 // <returns>
3407 // Returns an integer representing the
3408 // encoded value providedint he 1st 6
3409 // characters of the string.
3410 // </returns>
3411 // <remarks>
3412 // This is coded to behave like LSL's
3413 // implementation (I think), based upon the
3414 // information available at the Wiki.
3415 // If more than 8 characters are supplied,
3416 // zero is returned.
3417 // If a NULL string is supplied, zero will
3418 // be returned.
3419 // If fewer than 6 characters are supplied, then
3420 // the answer will reflect a partial
3421 // accumulation.
3422 // <para>
3423 // The 6-bit segments are
3424 // extracted left-to-right in big-endian mode,
3425 // which means that segment 6 only contains the
3426 // two low-order bits of the 32 bit integer as
3427 // its high order 2 bits. A short string therefore
3428 // means loss of low-order information. E.g.
3429 //
3430 // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
3431 // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
3432 // |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1| | | | | | | | | | |P|P|P|P|
3433 // |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|P|P|P|P|
3434 // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
3435 //
3436 // </para>
3437 // </remarks>
3253 3438
3254 public int llBase64ToInteger(string str) 3439 public int llBase64ToInteger(string str)
3255 { 3440 {
3441
3442 int number = 0;
3443 int digit;
3444 int baddigit = 0;
3445
3256 m_host.AddScriptLPS(1); 3446 m_host.AddScriptLPS(1);
3257 NotImplemented("llBase64ToInteger"); 3447
3258 return 0; 3448 // Require a well-fromed base64 string
3449
3450 if(str.Length > 8)
3451 return 0;
3452
3453 // The loop is unrolled in the interests
3454 // of performance and simple necessity.
3455 //
3456 // MUST find 6 digits to be well formed
3457 // -1 == invalid
3458 // 0 == padding
3459
3460 if((digit=c2itable[str[0]])<=0)
3461 {
3462 return digit<0?(int)0:number;
3463 }
3464 number += --digit<<26;
3465
3466 if((digit=c2itable[str[1]])<=0)
3467 {
3468 return digit<0?(int)0:number;
3469 }
3470 number += --digit<<20;
3471
3472 if((digit=c2itable[str[2]])<=0)
3473 {
3474 return digit<0?(int)0:number;
3475 }
3476 number += --digit<<14;
3477
3478 if((digit=c2itable[str[3]])<=0)
3479 {
3480 return digit<0?(int)0:number;
3481 }
3482 number += --digit<<8;
3483
3484 if((digit=c2itable[str[4]])<=0)
3485 {
3486 return digit<0?(int)0:number;
3487 }
3488 number += --digit<<2;
3489
3490 if((digit=c2itable[str[5]])<=0)
3491 {
3492 return digit<0?(int)0:number;
3493 }
3494 number += --digit>>4;
3495
3496 // ignore trailing padding
3497
3498 return number;
3499
3259 } 3500 }
3260 3501
3261 public double llGetGMTclock() 3502 public double llGetGMTclock()
@@ -3276,11 +3517,179 @@ namespace OpenSim.Region.ScriptEngine.Common
3276 m_host.RotationOffset = new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s); 3517 m_host.RotationOffset = new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
3277 } 3518 }
3278 3519
3279 public LSL_Types.list llParseStringKeepNulls(string src, LSL_Types.list seperators, LSL_Types.list spacers) 3520 // <summary>
3521 // Scan the string supplied in 'src' and
3522 // tokenize it based upon two sets of
3523 // tokenizers provided in two lists,
3524 // separators and spacers.
3525 // </summary>
3526 //
3527 // <remarks>
3528 // Separators demarcate tokens and are
3529 // elided as they are encountered. Spacers
3530 // also demarcate tokens, but are themselves
3531 // retained as tokens.
3532 //
3533 // Both separators and spacers may be arbitrarily
3534 // long strings. i.e. ":::".
3535 //
3536 // The function returns an ordered list
3537 // representing the tokens found in the supplied
3538 // sources string. If two successive tokenizers
3539 // are encountered, then a NULL entry is added
3540 // to the list.
3541 //
3542 // It is a precondition that the source and
3543 // toekizer lisst are non-null. If they are null,
3544 // then a null pointer exception will be thrown
3545 // while their lengths are being determined.
3546 //
3547 // A small amount of working memoryis required
3548 // of approximately 8*#tokenizers.
3549 //
3550 // There are many ways in which this function
3551 // can be implemented, this implementation is
3552 // fairly naive and assumes that when the
3553 // function is invooked with a short source
3554 // string and/or short lists of tokenizers, then
3555 // performance will not be an issue.
3556 //
3557 // In order to minimize the perofrmance
3558 // effects of long strings, or large numbers
3559 // of tokeizers, the function skips as far as
3560 // possible whenever a toekenizer is found,
3561 // and eliminates redundant tokenizers as soon
3562 // as is possible.
3563 //
3564 // The implementation tries to avoid any copying
3565 // of arrays or other objects.
3566 // </remarks>
3567
3568 public LSL_Types.list llParseStringKeepNulls(string src, LSL_Types.list separators, LSL_Types.list spacers)
3280 { 3569 {
3570
3571 int beginning = 0;
3572 int srclen = src.Length;
3573 int seplen = separators.Length;
3574 object[] separray = separators.Data;
3575 int spclen = spacers.Length;
3576 object[] spcarray = spacers.Data;
3577 int mlen = seplen+spclen;
3578
3579 int[] offset = new int[mlen+1];
3580 bool[] active = new bool[mlen];
3581
3582 int best;
3583 int j;
3584
3585 // Initial capacity reduces resize cost
3586
3587 LSL_Types.list tokens = new LSL_Types.list();
3588
3281 m_host.AddScriptLPS(1); 3589 m_host.AddScriptLPS(1);
3282 NotImplemented("llParseStringKeepNulls"); 3590
3283 return new LSL_Types.list(); 3591 // All entries are initially valid
3592
3593 for(int i=0; i<mlen; i++) active[i] = true;
3594
3595 offset[mlen] = srclen;
3596
3597 while(beginning<srclen)
3598 {
3599
3600 best = mlen; // as bad as it gets
3601
3602 // Scan for separators
3603
3604 for(j=0; j<seplen; j++)
3605 {
3606 if(active[j])
3607 {
3608 // scan all of the markers
3609 if((offset[j] = src.IndexOf((string)separray[j],beginning)) == -1)
3610 {
3611 // not present at all
3612 active[j] = false;
3613 } else
3614 {
3615 // present and correct
3616 if(offset[j] < offset[best])
3617 {
3618 // closest so far
3619 best = j;
3620 if(offset[best] == beginning)
3621 break;
3622 }
3623 }
3624 }
3625 }
3626
3627 // Scan for spacers
3628
3629 if(offset[best] != beginning)
3630 {
3631 for(j=seplen; (j<mlen) && (offset[best] > beginning); j++)
3632 {
3633 if(active[j])
3634 {
3635 // scan all of the markers
3636 if((offset[j] = src.IndexOf((string)spcarray[j-seplen],beginning)) == -1)
3637 {
3638 // not present at all
3639 active[j] = false;
3640 } else
3641 {
3642 // present and correct
3643 if(offset[j] < offset[best])
3644 {
3645 // closest so far
3646 best = j;
3647 }
3648 }
3649 }
3650 }
3651 }
3652
3653 // This is the normal exit from the scanning loop
3654
3655 if(best == mlen)
3656 {
3657 // no markers were found on this pass
3658 // so we're pretty much done
3659 tokens.Add(src.Substring(beginning, srclen-beginning));
3660 break;
3661 }
3662
3663 // Otherwise we just add the newly delimited token
3664 // and recalculate where the search should continue.
3665
3666 tokens.Add(src.Substring(beginning,offset[best]-beginning));
3667
3668 if(best<seplen)
3669 {
3670 beginning = offset[best]+((string)separray[best]).Length;
3671 } else
3672 {
3673 beginning = offset[best]+((string)spcarray[best-seplen]).Length;
3674 tokens.Add(spcarray[best-seplen]);
3675 }
3676
3677 }
3678
3679 // This an awkward an not very intuitive boundary case. If the
3680 // last substring is a tokenizer, then there is an implied trailing
3681 // null list entry. Hopefully the single comparison will not be too
3682 // arduous. Alternatively the 'break' could be replced with a return
3683 // but that's shabby programming.
3684
3685 if(beginning == srclen)
3686 {
3687 if(srclen != 0)
3688 tokens.Add("");
3689 }
3690
3691 return tokens;
3692
3284 } 3693 }
3285 3694
3286 public void llRezAtRoot(string inventory, LSL_Types.Vector3 position, LSL_Types.Vector3 velocity, 3695 public void llRezAtRoot(string inventory, LSL_Types.Vector3 position, LSL_Types.Vector3 velocity,