aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs2031
1 files changed, 2031 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs
new file mode 100644
index 0000000..802eac2
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs
@@ -0,0 +1,2031 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
29using System;
30using System.Collections.Generic;
31using System.Globalization;
32using System.IO;
33using System.Reflection.Emit;
34using System.Runtime.Serialization;
35using System.Text;
36using System.Threading;
37
38using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
39using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
40using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
41using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
42using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
43using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
44using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
45
46namespace OpenSim.Region.ScriptEngine.XMREngine
47{
48 public class XMRInstArrays {
49 public XMR_Array[] iarArrays;
50 public char[] iarChars;
51 public double[] iarFloats;
52 public int[] iarIntegers;
53 public LSL_List[] iarLists;
54 public object[] iarObjects;
55 public LSL_Rotation[] iarRotations;
56 public string[] iarStrings;
57 public LSL_Vector[] iarVectors;
58 public XMRSDTypeClObj[] iarSDTClObjs;
59 public Delegate[][] iarSDTIntfObjs;
60
61 private XMRInstAbstract instance;
62 private int heapUse;
63
64 private static readonly XMR_Array[] noArrays = new XMR_Array[0];
65 private static readonly char[] noChars = new char[0];
66 private static readonly double[] noFloats = new double[0];
67 private static readonly int[] noIntegers = new int[0];
68 private static readonly LSL_List[] noLists = new LSL_List[0];
69 private static readonly object[] noObjects = new object[0];
70 private static readonly LSL_Rotation[] noRotations = new LSL_Rotation[0];
71 private static readonly string[] noStrings = new string[0];
72 private static readonly LSL_Vector[] noVectors = new LSL_Vector[0];
73 private static readonly XMRSDTypeClObj[] noSDTClObjs = new XMRSDTypeClObj[0];
74 private static readonly Delegate[][] noSDTIntfObjs = new Delegate[0][];
75
76 public XMRInstArrays (XMRInstAbstract inst)
77 {
78 instance = inst;
79 }
80
81 ~XMRInstArrays ()
82 {
83 heapUse = instance.UpdateHeapUse (heapUse, 0);
84 }
85
86 public void AllocVarArrays (XMRInstArSizes ars)
87 {
88 ClearOldArrays ();
89
90 heapUse = instance.UpdateHeapUse (heapUse,
91 ars.iasChars * HeapTrackerObject.HT_CHAR +
92 ars.iasFloats * HeapTrackerObject.HT_SFLT +
93 ars.iasIntegers * HeapTrackerObject.HT_INT +
94 ars.iasRotations * HeapTrackerObject.HT_ROT +
95 ars.iasVectors * HeapTrackerObject.HT_VEC +
96 ars.iasSDTIntfObjs * HeapTrackerObject.HT_DELE);
97
98 iarArrays = (ars.iasArrays > 0) ? new XMR_Array [ars.iasArrays] : noArrays;
99 iarChars = (ars.iasChars > 0) ? new char [ars.iasChars] : noChars;
100 iarFloats = (ars.iasFloats > 0) ? new double [ars.iasFloats] : noFloats;
101 iarIntegers = (ars.iasIntegers > 0) ? new int [ars.iasIntegers] : noIntegers;
102 iarLists = (ars.iasLists > 0) ? new LSL_List [ars.iasLists] : noLists;
103 iarObjects = (ars.iasObjects > 0) ? new object [ars.iasObjects] : noObjects;
104 iarRotations = (ars.iasRotations > 0) ? new LSL_Rotation [ars.iasRotations] : noRotations;
105 iarStrings = (ars.iasStrings > 0) ? new string [ars.iasStrings] : noStrings;
106 iarVectors = (ars.iasVectors > 0) ? new LSL_Vector [ars.iasVectors] : noVectors;
107 iarSDTClObjs = (ars.iasSDTClObjs > 0) ? new XMRSDTypeClObj[ars.iasSDTClObjs] : noSDTClObjs;
108 iarSDTIntfObjs = (ars.iasSDTIntfObjs > 0) ? new Delegate [ars.iasSDTIntfObjs][] : noSDTIntfObjs;
109 }
110
111 /**
112 * @brief Do not write directly to iarLists[index], rather use this method.
113 */
114 public void PopList (int index, LSL_List lis)
115 {
116 LSL_List old = iarLists[index];
117 int newheapuse = heapUse + HeapTrackerList.Size (lis) - HeapTrackerList.Size (old);
118 heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
119 iarLists[index] = lis;
120 }
121
122 /**
123 * @brief Do not write directly to iarObjects[index], rather use this method.
124 */
125 public void PopObject (int index, object obj)
126 {
127 object old = iarObjects[index];
128 int newheapuse = heapUse + HeapTrackerObject.Size (obj) - HeapTrackerObject.Size (old);
129 heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
130 iarObjects[index] = obj;
131 }
132
133 /**
134 * @brief Do not write directly to iarStrings[index], rather use this method.
135 */
136 public void PopString (int index, string str)
137 {
138 string old = iarStrings[index];
139 int newheapuse = heapUse + HeapTrackerString.Size (str) - HeapTrackerString.Size (old);
140 heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
141 iarStrings[index] = str;
142 }
143
144 /**
145 * @brief Write all arrays out to a file.
146 */
147 public delegate void Sender (object value);
148 public void SendArrays (Sender sender)
149 {
150 sender (iarArrays);
151 sender (iarChars);
152 sender (iarFloats);
153 sender (iarIntegers);
154 sender (iarLists);
155 sender (iarObjects);
156 sender (iarRotations);
157 sender (iarStrings);
158 sender (iarVectors);
159 sender (iarSDTClObjs);
160 sender (iarSDTIntfObjs);
161 }
162
163 /**
164 * @brief Read all arrays in from a file.
165 */
166 public delegate object Recver ();
167 public void RecvArrays (Recver recver)
168 {
169 ClearOldArrays ();
170
171 iarArrays = (XMR_Array[]) recver ();
172 char[] chrs = (char[]) recver ();
173 double[] flts = (double[]) recver ();
174 int[] ints = (int[]) recver ();
175 LSL_List[] liss = (LSL_List[]) recver ();
176 object[] objs = (object[]) recver ();
177 LSL_Rotation[] rots = (LSL_Rotation[]) recver ();
178 string[] strs = (string[]) recver ();
179 LSL_Vector[] vecs = (LSL_Vector[]) recver ();
180 iarSDTClObjs = (XMRSDTypeClObj[]) recver ();
181 Delegate[][] dels = (Delegate[][]) recver ();
182
183 int newheapuse = heapUse;
184
185 // value types simply are the size of the value * number of values
186 newheapuse += chrs.Length * HeapTrackerObject.HT_CHAR;
187 newheapuse += flts.Length * HeapTrackerObject.HT_SFLT;
188 newheapuse += ints.Length * HeapTrackerObject.HT_INT;
189 newheapuse += rots.Length * HeapTrackerObject.HT_ROT;
190 newheapuse += vecs.Length * HeapTrackerObject.HT_VEC;
191 newheapuse += dels.Length * HeapTrackerObject.HT_DELE;
192
193 // lists, objects, strings are the sum of the size of each element
194 foreach (LSL_List lis in liss) {
195 newheapuse += HeapTrackerList.Size (lis);
196 }
197 foreach (object obj in objs) {
198 newheapuse += HeapTrackerObject.Size (obj);
199 }
200 foreach (string str in strs) {
201 newheapuse += HeapTrackerString.Size (str);
202 }
203
204 // others (XMR_Array, XMRSDTypeClObj) keep track of their own heap usage
205
206 // update script heap usage, throwing an exception before finalizing changes
207 heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
208
209 iarChars = chrs;
210 iarFloats = flts;
211 iarIntegers = ints;
212 iarLists = liss;
213 iarObjects = objs;
214 iarRotations = rots;
215 iarStrings = strs;
216 iarVectors = vecs;
217 iarSDTIntfObjs = dels;
218 }
219
220 private void ClearOldArrays ()
221 {
222 int newheapuse = heapUse;
223
224 iarArrays = null;
225 if (iarChars != null) {
226 newheapuse -= iarChars.Length * HeapTrackerObject.HT_CHAR;
227 iarChars = null;
228 }
229 if (iarFloats != null) {
230 newheapuse -= iarFloats.Length * HeapTrackerObject.HT_SFLT;
231 iarFloats = null;
232 }
233 if (iarIntegers != null) {
234 newheapuse -= iarIntegers.Length * HeapTrackerObject.HT_INT;
235 iarIntegers = null;
236 }
237 if (iarLists != null) {
238 foreach (LSL_List lis in iarLists) {
239 newheapuse -= HeapTrackerList.Size (lis);
240 }
241 iarLists = null;
242 }
243 if (iarObjects != null) {
244 foreach (object obj in iarObjects) {
245 newheapuse -= HeapTrackerObject.Size (obj);
246 }
247 iarObjects = null;
248 }
249 if (iarRotations != null) {
250 newheapuse -= iarRotations.Length * HeapTrackerObject.HT_ROT;
251 iarRotations = null;
252 }
253 if (iarStrings != null) {
254 foreach (string str in iarStrings) {
255 newheapuse -= HeapTrackerString.Size (str);
256 }
257 iarStrings = null;
258 }
259 if (iarVectors != null) {
260 newheapuse -= iarVectors.Length * HeapTrackerObject.HT_VEC;
261 iarVectors = null;
262 }
263 iarSDTClObjs = null;
264 if (iarSDTIntfObjs != null) {
265 newheapuse -= iarSDTIntfObjs.Length * HeapTrackerObject.HT_DELE;
266 iarSDTIntfObjs = null;
267 }
268
269 heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
270 }
271 }
272
273 public class XMRInstArSizes {
274 public int iasArrays;
275 public int iasChars;
276 public int iasFloats;
277 public int iasIntegers;
278 public int iasLists;
279 public int iasObjects;
280 public int iasRotations;
281 public int iasStrings;
282 public int iasVectors;
283 public int iasSDTClObjs;
284 public int iasSDTIntfObjs;
285
286 public void WriteAsmFile (TextWriter asmFileWriter, string label)
287 {
288 asmFileWriter.WriteLine (" {0}Arrays {1}", label, iasArrays);
289 asmFileWriter.WriteLine (" {0}Chars {1}", label, iasChars);
290 asmFileWriter.WriteLine (" {0}Floats {1}", label, iasFloats);
291 asmFileWriter.WriteLine (" {0}Integers {1}", label, iasIntegers);
292 asmFileWriter.WriteLine (" {0}Lists {1}", label, iasLists);
293 asmFileWriter.WriteLine (" {0}Objects {1}", label, iasObjects);
294 asmFileWriter.WriteLine (" {0}Rotations {1}", label, iasRotations);
295 asmFileWriter.WriteLine (" {0}Strings {1}", label, iasStrings);
296 asmFileWriter.WriteLine (" {0}Vectors {1}", label, iasVectors);
297 asmFileWriter.WriteLine (" {0}SDTClObjs {1}", label, iasSDTClObjs);
298 asmFileWriter.WriteLine (" {0}SDTIntfObjs {1}", label, iasSDTIntfObjs);
299 }
300 public void WriteToFile (BinaryWriter objFileWriter)
301 {
302 objFileWriter.Write (iasArrays);
303 objFileWriter.Write (iasChars);
304 objFileWriter.Write (iasFloats);
305 objFileWriter.Write (iasIntegers);
306 objFileWriter.Write (iasLists);
307 objFileWriter.Write (iasObjects);
308 objFileWriter.Write (iasRotations);
309 objFileWriter.Write (iasStrings);
310 objFileWriter.Write (iasVectors);
311 objFileWriter.Write (iasSDTClObjs);
312 objFileWriter.Write (iasSDTIntfObjs);
313 }
314 public void ReadFromFile (BinaryReader objFileReader)
315 {
316 iasArrays = objFileReader.ReadInt32 ();
317 iasChars = objFileReader.ReadInt32 ();
318 iasFloats = objFileReader.ReadInt32 ();
319 iasIntegers = objFileReader.ReadInt32 ();
320 iasLists = objFileReader.ReadInt32 ();
321 iasObjects = objFileReader.ReadInt32 ();
322 iasRotations = objFileReader.ReadInt32 ();
323 iasStrings = objFileReader.ReadInt32 ();
324 iasVectors = objFileReader.ReadInt32 ();
325 iasSDTClObjs = objFileReader.ReadInt32 ();
326 iasSDTIntfObjs = objFileReader.ReadInt32 ();
327 }
328 }
329
330 public class XMRStackFrame {
331 public XMRStackFrame nextSF;
332 public string funcName;
333 public int callNo;
334 public object[] objArray;
335 }
336
337 /*
338 * Contains only items required by the stand-alone compiler
339 * so the compiler doesn't need to pull in all of OpenSim.
340 *
341 * Inherit from ScriptBaseClass so we can be used as 'this'
342 * parameter for backend-API calls, eg llSay().
343 */
344 public abstract class XMRInstAbstract : ScriptBaseClass
345 {
346 public const int CallMode_NORMAL = 0; // when function is called, it proceeds normally
347 public const int CallMode_SAVE = 1; // StackSaveException() was thrown, push args/locals to stackFrames
348 public const int CallMode_RESTORE = 2; // when function is called, it pops state from stackFrames
349
350 public bool suspendOnCheckRunHold; // suspend script execution until explicitly set false
351 public bool suspendOnCheckRunTemp; // suspend script execution for single step only
352 public int stackLimit; // stack must have at least this many bytes free on entry to functions
353
354 public ScriptObjCode m_ObjCode; // script object code this instance was created from
355
356 public object[] ehArgs; // event handler argument array
357 public bool doGblInit = true; // default state_entry() needs to initialize global variables
358 public int stateCode = 0; // state the script is in (0 = 'default')
359 public int newStateCode = -1; // if >= 0, in the middle of exiting 'stateCode' and entering 'newStateCode'
360 public ScriptEventCode eventCode = ScriptEventCode.None;
361 // what event handler is executing (or None if not)
362
363 public int callMode = CallMode_NORMAL;
364 // to capture stack frames on stackFrames:
365 // set to CallMode_SAVE just before throwing StackSaveException()
366 // from within CheckRun() and cleared to CallMode_NORMAL when
367 // the exception is caught
368 // to restore stack frames from stackFrames:
369 // set to CallMode_RESTORE just before calling CallSEH() and
370 // cleared to CallMode_NORMAL by CheckRun()
371 public XMRStackFrame stackFrames; // stack frames being saved/restored
372
373 private static readonly char[] justacomma = { ',' };
374
375 /*
376 * These arrays hold the global variable values for the script instance.
377 * The array lengths are determined by the script compilation,
378 * and are found in ScriptObjCode.glblSizes.
379 */
380 public XMRInstArrays glblVars;
381
382 public XMRInstAbstract ()
383 {
384 glblVars = new XMRInstArrays (this);
385 }
386
387 /****************************************************************\
388 * Abstract function prototypes. *
389 * These functions require access to the OpenSim environment. *
390 \****************************************************************/
391
392 public abstract void CheckRunWork ();
393 public abstract void StateChange ();
394 public abstract int xmrStackLeft ();
395
396 [xmrMethodCallsCheckRunAttribute] // calls CheckRun()
397 [xmrMethodIsNoisyAttribute] // calls Stub<somethingorother>()
398 public abstract LSL_List xmrEventDequeue (double timeout, int returnMask1, int returnMask2,
399 int backgroundMask1, int backgroundMask2);
400
401 [xmrMethodIsNoisyAttribute] // calls Stub<somethingorother>()
402 public abstract void xmrEventEnqueue (LSL_List ev);
403
404 [xmrMethodIsNoisyAttribute] // calls Stub<somethingorother>()
405 public abstract LSL_List xmrEventSaveDets ();
406
407 [xmrMethodIsNoisyAttribute] // calls Stub<somethingorother>()
408 public abstract void xmrEventLoadDets (LSL_List dpList);
409
410 [xmrMethodIsNoisyAttribute] // calls Stub<somethingorother>()
411 public abstract void xmrTrapRegionCrossing (int en);
412
413 [xmrMethodIsNoisyAttribute] // calls Stub<somethingorother>()
414 public abstract bool xmrSetObjRegPosRotAsync (LSL_Vector pos, LSL_Rotation rot, int options, int evcode, LSL_List evargs);
415
416 /************************************\
417 * Constants available to scripts *
418 \************************************/
419
420 public const int XMRSORPRA_FLYACROSS = 0x00000001;
421
422 /**************************************************\
423 * Functions what don't require runtime support *
424 * beyond what the compiler provides. *
425 \**************************************************/
426
427 protected int heapLimit;
428 private int heapUsed;
429
430 public virtual int UpdateHeapUse (int olduse, int newuse)
431 {
432 if (newuse <= olduse) {
433 Interlocked.Add (ref heapUsed, newuse - olduse);
434 } else {
435 int newtotal, oldtotal;
436 do {
437 oldtotal = Interlocked.Add (ref heapUsed, 0);
438 newtotal = oldtotal + newuse - olduse;
439 if (newtotal > heapLimit) {
440 System.GC.Collect ();
441 System.GC.WaitForPendingFinalizers ();
442 oldtotal = Interlocked.Add (ref heapUsed, 0);
443 newtotal = oldtotal + newuse - olduse;
444 if (newtotal > heapLimit) {
445 throw new OutOfHeapException (oldtotal, newtotal, heapLimit);
446 }
447 }
448 } while (Interlocked.CompareExchange (ref heapUsed, newtotal, oldtotal) != oldtotal);
449 }
450
451 return newuse;
452 }
453
454 public int xmrHeapLeft ()
455 {
456 return heapLimit - heapUsed;
457 }
458 public int xmrHeapUsed ()
459 {
460 return heapUsed;
461 }
462
463 /**
464 * @brief Call script's event handler function from the very beginning.
465 * @param instance.stateCode = which state the event is happening in
466 * @param instance.eventCode = which event is happening in that state
467 * @returns when event handler has completed or throws an exception
468 * with instance.eventCode = ScriptEventCode.None
469 */
470 public void CallSEH ()
471 {
472 ScriptEventHandler seh;
473
474 /*
475 * CallMode_NORMAL: run event handler from the beginning normally
476 * CallMode_RESTORE: restore event handler stack from stackFrames
477 */
478 callMode = (stackFrames == null) ? XMRInstAbstract.CallMode_NORMAL :
479 XMRInstAbstract.CallMode_RESTORE;
480
481 while (true) {
482 if (this.newStateCode < 0) {
483
484 /*
485 * Process event given by 'stateCode' and 'eventCode'.
486 * The event handler should call CheckRun() as often as convenient.
487 */
488 int newState = this.stateCode;
489 seh = this.m_ObjCode.scriptEventHandlerTable[newState,(int)this.eventCode];
490 if (seh != null) {
491 try {
492 seh (this);
493 } catch (ScriptChangeStateException scse) {
494 newState = scse.newState;
495 }
496 }
497 this.ehArgs = null; // we are done with them and no args for
498 // exit_state()/enter_state() anyway
499
500 /*
501 * The usual case is no state change.
502 * Even a 'state <samestate>;' statement has no effect except to exit out.
503 * It does not execute the state_exit() or state_entry() handlers.
504 * See http://wiki.secondlife.com/wiki/State
505 */
506 if (newState == this.stateCode) break;
507
508 /*
509 * Save new state in a more permanent location in case we
510 * get serialized out while in the state_exit() handler.
511 */
512 this.newStateCode = newState;
513 }
514
515 /*
516 * Call old state's state_exit() handler.
517 */
518 this.eventCode = ScriptEventCode.state_exit;
519 seh = this.m_ObjCode.scriptEventHandlerTable[this.stateCode,(int)ScriptEventCode.state_exit];
520 if (seh != null) {
521 try {
522 seh (this);
523 } catch (ScriptChangeStateException scse) {
524 this.newStateCode = scse.newState;
525 }
526 }
527
528 /*
529 * Switch over to the new state's state_entry() handler.
530 */
531 this.stateCode = this.newStateCode;
532 this.eventCode = ScriptEventCode.state_entry;
533 this.newStateCode = -1;
534
535 /*
536 * Now that the old state can't possibly start any more activity,
537 * cancel any listening handlers, etc, of the old state.
538 */
539 this.StateChange ();
540
541 /*
542 * Loop back to execute new state's state_entry() handler.
543 */
544 }
545
546 /*
547 * Event no longer being processed.
548 */
549 this.eventCode = ScriptEventCode.None;
550 }
551
552 /**
553 * @brief For compatibility with old code.
554 */
555 public void CheckRun (int line)
556 {
557 CheckRunStack ();
558 }
559
560 /**
561 * @brief Called at beginning of complex functions to see if they
562 * are nested too deep possibly in a recursive loop.
563 */
564 public void CheckRunStack ()
565 {
566 if (xmrStackLeft () < stackLimit) {
567 throw new OutOfStackException ();
568 }
569 CheckRunQuick ();
570 }
571
572 /**
573 * @brief Called in each iteration of a loop to see if running too long.
574 */
575 public void CheckRunQuick ()
576 {
577 if (suspendOnCheckRunHold || suspendOnCheckRunTemp) {
578 CheckRunWork ();
579 }
580 }
581
582 /**
583 * @brief Called during CallMode_SAVE to create a stackframe save object that saves
584 * local variables and calling point within the function.
585 * @param funcName = name of function whose frame is being saved
586 * @param callNo = call number (ie, return address) within function to restart at
587 * @param nSaves = number of variables the function will save
588 * @returns an object[nSaves] where function can save variables
589 */
590 public object[] CaptureStackFrame (string funcName, int callNo, int nSaves)
591 {
592 XMRStackFrame sf = new XMRStackFrame ();
593 sf.nextSF = stackFrames;
594 sf.funcName = funcName;
595 sf.callNo = callNo;
596 sf.objArray = new object[nSaves];
597 stackFrames = sf;
598 return sf.objArray;
599 }
600
601 /**
602 * @brief Called during CallMode_RESTORE to pop a stackframe object to restore
603 * local variables and calling point within the function.
604 * @param funcName = name of function whose frame is being restored
605 * @returns the object[nSaves] where function can retrieve variables
606 * callNo = as passed to CaptureStackFrame() indicating restart point
607 */
608 public object[] RestoreStackFrame (string funcName, out int callNo)
609 {
610 XMRStackFrame sf = stackFrames;
611 if (sf.funcName != funcName) {
612 throw new Exception ("frame mismatch " + sf.funcName + " vs " + funcName);
613 }
614 callNo = sf.callNo;
615 stackFrames = sf.nextSF;
616 return sf.objArray;
617 }
618
619 /**
620 * @brief Convert all LSL_Integers in a list to System.Int32s,
621 * as required by llParcelMediaQuery().
622 */
623 public static LSL_List FixLLParcelMediaQuery (LSL_List oldlist)
624 {
625 object[] oldarray = oldlist.Data;
626 int len = oldarray.Length;
627 object[] newarray = new object[len];
628 for (int i = 0; i < len; i ++) {
629 object obj = oldarray[i];
630 if (obj is LSL_Integer) obj = (int)(LSL_Integer)obj;
631 newarray[i] = obj;
632 }
633 return new LSL_List (newarray);
634 }
635
636 /**
637 * @brief Convert *SOME* LSL_Integers in a list to System.Int32s,
638 * as required by llParcelMediaCommandList().
639 */
640 public static LSL_List FixLLParcelMediaCommandList (LSL_List oldlist)
641 {
642 object[] oldarray = oldlist.Data;
643 int len = oldarray.Length;
644 object[] newarray = new object[len];
645 int verbatim = 0;
646 for (int i = 0; i < len; i ++) {
647 object obj = oldarray[i];
648 if (-- verbatim < 0) {
649 if (obj is LSL_Integer) obj = (int)(LSL_Integer)obj;
650 if (obj is int) {
651 switch ((int)obj) {
652 case ScriptBaseClass.PARCEL_MEDIA_COMMAND_AUTO_ALIGN: {
653 // leave next integer as LSL_Integer
654 verbatim = 1;
655 break;
656 }
657 case ScriptBaseClass.PARCEL_MEDIA_COMMAND_SIZE: {
658 // leave next two integers as LSL_Integer
659 verbatim = 2;
660 break;
661 }
662 }
663 }
664 }
665 newarray[i] = obj;
666 }
667 return new LSL_List (newarray);
668 }
669
670 public static int xmrHashCode (int i)
671 {
672 return i.GetHashCode ();
673 }
674 public static int xmrHashCode (double f)
675 {
676 return f.GetHashCode ();
677 }
678 public static int xmrHashCode (object o)
679 {
680 return o.GetHashCode ();
681 }
682 public static int xmrHashCode (string s)
683 {
684 return s.GetHashCode ();
685 }
686
687 public bool xmrSetObjRegPosRotAsync (LSL_Vector pos, LSL_Rotation rot, int evcode, LSL_List evargs)
688 {
689 return xmrSetObjRegPosRotAsync (pos, rot, 0, evcode, evargs);
690 }
691
692 public string xmrTypeName (object o)
693 {
694 /*
695 * Basic types return constant strings of the script-visible type name.
696 */
697 if (o is XMR_Array) return "array";
698 if (o is bool) return "bool";
699 if (o is char) return "char";
700 if (o is Exception) return "exception";
701 if (o is double) return "float";
702 if (o is float) return "float";
703 if (o is LSL_Float) return "float";
704 if (o is int) return "integer";
705 if (o is LSL_Integer) return "integer";
706 if (o is LSL_List) return "list";
707 if (o is LSL_Rotation) return "rotation";
708 if (o is LSL_String) return "string";
709 if (o is string) return "string";
710 if (o is LSL_Vector) return "vector";
711
712 /*
713 * A script-defined interface is represented as an array of delegates.
714 * If that is the case, convert it to the object of the script-defined
715 * class that is implementing the interface. This should let the next
716 * step get the script-defined type name of the object.
717 */
718 if (o is Delegate[]) {
719 o = ((Delegate[])o)[0].Target;
720 }
721
722 /*
723 * If script-defined class instance, get the script-defined
724 * type name.
725 */
726 if (o is XMRSDTypeClObj) {
727 return ((XMRSDTypeClObj)o).sdtcClass.longName.val;
728 }
729
730 /*
731 * If it's a delegate, maybe we can look up its script-defined type name.
732 */
733 Type ot = o.GetType ();
734 if (o is Delegate) {
735 String os;
736 if (m_ObjCode.sdDelTypes.TryGetValue (ot, out os)) return os;
737 }
738
739 /*
740 * Don't know what it is, get the C#-level type name.
741 */
742 return ot.ToString ();
743 }
744
745 /**
746 * @brief Call the current state's event handler.
747 * @param ev = as returned by xmrEventDequeue saying which event handler to call
748 * and what argument list to pass to it. The llDetect...() parameters
749 * are as currently set for the script (use xmrEventLoadDets to set how
750 * you want them to be different).
751 */
752 public void xmrEventCallHandler (LSL_List ev)
753 {
754 object[] data = ev.Data;
755 int evc = (int)(ev.GetLSLIntegerItem (0).value & 0xFFFFFFFF);
756 ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode,evc];
757 if (seh != null) {
758 int nargs = data.Length - 1;
759 object[] args = new object[nargs];
760 Array.Copy (data, 1, args, 0, nargs);
761
762 object[] saveEHArgs = this.ehArgs;
763 ScriptEventCode saveEventCode = this.eventCode;
764
765 this.ehArgs = args;
766 this.eventCode = (ScriptEventCode)evc;
767
768 seh (this);
769
770 this.ehArgs = saveEHArgs;
771 this.eventCode = saveEventCode;
772 }
773 }
774
775 /**
776 * @brief Sane substring functions.
777 */
778 public string xmrSubstring (string s, int offset)
779 {
780 if (offset >= s.Length) return "";
781 return s.Substring (offset);
782 }
783 // C# style
784 public string xmrSubstring (string s, int offset, int length)
785 {
786 if (length <= 0) return "";
787 if (offset >= s.Length) return "";
788 if (length > s.Length - offset) length = s.Length - offset;
789 return s.Substring (offset, length);
790 }
791 // java style
792 public string xmrJSubstring (string s, int beg, int end)
793 {
794 if (end <= beg) return "";
795 if (beg >= s.Length) return "";
796 if (end > s.Length) end = s.Length;
797 return s.Substring (beg, end - beg);
798 }
799
800 /**
801 * @brief String begins and ends with test.
802 */
803 public bool xmrStringStartsWith (string s, string t)
804 {
805 return s.StartsWith (t);
806 }
807 public bool xmrStringEndsWith (string s, string t)
808 {
809 return s.EndsWith (t);
810 }
811
812 /**
813 * @brief [Last]IndexOf with starting position (just like C#)
814 */
815 public int xmrStringIndexOf (string haystack, string needle)
816 {
817 return haystack.IndexOf (needle);
818 }
819 public int xmrStringIndexOf (string haystack, string needle, int startat)
820 {
821 return haystack.IndexOf (needle, startat);
822 }
823 public int xmrStringLastIndexOf (string haystack, string needle)
824 {
825 return haystack.LastIndexOf (needle);
826 }
827 public int xmrStringLastIndexOf (string haystack, string needle, int startat)
828 {
829 return haystack.LastIndexOf (needle, startat);
830 }
831
832 /**
833 * @brief These conversions throw exceptions if there is anything stinky...
834 */
835 public double xmrString2Float (string s)
836 {
837 return double.Parse (s, CultureInfo.InvariantCulture);
838 }
839 public int xmrString2Integer (string s)
840 {
841 s = s.Trim ();
842 if (s.StartsWith ("0x") || s.StartsWith ("0X")) {
843 return int.Parse (s.Substring (2), NumberStyles.HexNumber);
844 }
845 return int.Parse (s, CultureInfo.InvariantCulture);
846 }
847 public LSL_Rotation xmrString2Rotation (string s)
848 {
849 s = s.Trim ();
850 if (!s.StartsWith ("<") || !s.EndsWith (">")) {
851 throw new FormatException ("doesn't begin with < and end with >");
852 }
853 s = s.Substring (1, s.Length - 2);
854 string[] splitup = s.Split (justacomma, 5);
855 if (splitup.Length != 4) {
856 throw new FormatException ("doesn't have exactly 3 commas");
857 }
858 double x = double.Parse (splitup[0], CultureInfo.InvariantCulture);
859 double y = double.Parse (splitup[1], CultureInfo.InvariantCulture);
860 double z = double.Parse (splitup[2], CultureInfo.InvariantCulture);
861 double w = double.Parse (splitup[3], CultureInfo.InvariantCulture);
862 return new LSL_Rotation (x, y, z, w);
863 }
864 public LSL_Vector xmrString2Vector (string s)
865 {
866 s = s.Trim ();
867 if (!s.StartsWith ("<") || !s.EndsWith (">")) {
868 throw new FormatException ("doesn't begin with < and end with >");
869 }
870 s = s.Substring (1, s.Length - 2);
871 string[] splitup = s.Split (justacomma, 4);
872 if (splitup.Length != 3) {
873 throw new FormatException ("doesn't have exactly 2 commas");
874 }
875 double x = double.Parse (splitup[0], CultureInfo.InvariantCulture);
876 double y = double.Parse (splitup[1], CultureInfo.InvariantCulture);
877 double z = double.Parse (splitup[2], CultureInfo.InvariantCulture);
878 return new LSL_Vector (x, y, z);
879 }
880
881 /**
882 * @brief Access C#-style formatted numeric conversions.
883 */
884 public string xmrFloat2String (double val, string fmt)
885 {
886 return val.ToString (fmt, CultureInfo.InvariantCulture);
887 }
888 public string xmrInteger2String (int val, string fmt)
889 {
890 return val.ToString (fmt, CultureInfo.InvariantCulture);
891 }
892 public string xmrRotation2String (LSL_Rotation val, string fmt)
893 {
894 return "<" + val.x.ToString (fmt, CultureInfo.InvariantCulture) + "," +
895 val.y.ToString (fmt, CultureInfo.InvariantCulture) + "," +
896 val.z.ToString (fmt, CultureInfo.InvariantCulture) + "," +
897 val.s.ToString (fmt, CultureInfo.InvariantCulture) + ">";
898 }
899 public string xmrVector2String (LSL_Vector val, string fmt)
900 {
901 return "<" + val.x.ToString (fmt, CultureInfo.InvariantCulture) + "," +
902 val.y.ToString (fmt, CultureInfo.InvariantCulture) + "," +
903 val.z.ToString (fmt, CultureInfo.InvariantCulture) + ">";
904 }
905
906 /**
907 * @brief Get a delegate for a script-defined function.
908 * @param name = name of the function including arg types, eg,
909 * "Verify(array,list,string)"
910 * @param sig = script-defined type name
911 * @param targ = function's 'this' pointer or null if static
912 * @returns delegate for the script-defined function
913 */
914 public Delegate GetScriptMethodDelegate (string name, string sig, object targ)
915 {
916 DynamicMethod dm = m_ObjCode.dynamicMethods[name];
917 TokenDeclSDTypeDelegate dt = (TokenDeclSDTypeDelegate)m_ObjCode.sdObjTypesName[sig];
918 return dm.CreateDelegate (dt.GetSysType (), targ);
919 }
920
921 /**
922 * @brief Try to cast the thrown object to the given script-defined type.
923 * @param thrown = what object was thrown
924 * @param inst = what script instance we are running in
925 * @param sdtypeindex = script-defined type to try to cast it to
926 * @returns null: thrown is not castable to sdtypename
927 * else: an object casted to sdtypename
928 */
929 public static object XMRSDTypeCatchTryCastToSDType (object thrown, XMRInstAbstract inst, int sdtypeindex)
930 {
931 TokenDeclSDType sdType = inst.m_ObjCode.sdObjTypesIndx[sdtypeindex];
932
933 /*
934 * If it is a script-defined interface object, convert to the original XMRSDTypeClObj.
935 */
936 if (thrown is Delegate[]) {
937 thrown = ((Delegate[])thrown)[0].Target;
938 }
939
940 /*
941 * If it is a script-defined delegate object, make sure it is an instance of the expected type.
942 */
943 if (thrown is Delegate) {
944 Type ot = thrown.GetType ();
945 Type tt = sdType.GetSysType ();
946 return (ot == tt) ? thrown : null;
947 }
948
949 /*
950 * If it is a script-defined class object, make sure it is an instance of the expected class.
951 */
952 if (thrown is XMRSDTypeClObj) {
953
954 /*
955 * Step from the object's actual class rootward.
956 * If we find the requested class along the way, the cast is valid.
957 * If we run off the end of the root, the cast is not valid.
958 */
959 for (TokenDeclSDTypeClass ac = ((XMRSDTypeClObj)thrown).sdtcClass; ac != null; ac = ac.extends) {
960 if (ac == sdType) return thrown;
961 }
962 }
963
964 /*
965 * Don't know what it is, assume it is not what caller wants.
966 */
967 return null;
968 }
969
970 /**
971 * @brief Allocate and access fixed-dimension arrays.
972 */
973 public static object xmrFixedArrayAllocC (int len) { return new char[len]; }
974 public static object xmrFixedArrayAllocF (int len) { return new double[len]; }
975 public static object xmrFixedArrayAllocI (int len) { return new int[len]; }
976 public static object xmrFixedArrayAllocO (int len) { return new object[len]; }
977
978 public static char xmrFixedArrayGetC (object arr, int idx) { return ( (char[])arr)[idx]; }
979 public static double xmrFixedArrayGetF (object arr, int idx) { return ((double[])arr)[idx]; }
980 public static int xmrFixedArrayGetI (object arr, int idx) { return ( (int[])arr)[idx]; }
981 public static object xmrFixedArrayGetO (object arr, int idx) { return ((object[])arr)[idx]; }
982
983 public static void xmrFixedArraySetC (object arr, int idx, char val) { ((char[])arr)[idx] = val; }
984 public static void xmrFixedArraySetF (object arr, int idx, double val) { ((double[])arr)[idx] = val; }
985 public static void xmrFixedArraySetI (object arr, int idx, int val) { ((int[])arr)[idx] = val; }
986 public static void xmrFixedArraySetO (object arr, int idx, object val) { ((object[])arr)[idx] = val; }
987
988 /**
989 * @brief Copy from one script-defined array to another.
990 * @param srcobj = source script-defined array class object pointer
991 * @param srcstart = offset in source array to start copying from
992 * @param dstobj = destination script-defined array class object pointer
993 * @param dststart = offset in destination arry to start copying to
994 * @param count = number of elements to copy
995 */
996 public static void xmrArrayCopy (object srcobj, int srcstart, object dstobj, int dststart, int count)
997 {
998 /*
999 * The script writer should only pass us script-defined class objects.
1000 * Throw exception otherwise.
1001 */
1002 XMRSDTypeClObj srcsdt = (XMRSDTypeClObj)srcobj;
1003 XMRSDTypeClObj dstsdt = (XMRSDTypeClObj)dstobj;
1004
1005 /*
1006 * Get the script-visible type name of the arrays, brackets and all.
1007 */
1008 string srctypename = srcsdt.sdtcClass.longName.val;
1009 string dsttypename = dstsdt.sdtcClass.longName.val;
1010
1011 /*
1012 * The part before the first '[' of each should match exactly,
1013 * meaning the basic data type (eg, float, List<string>) is the same.
1014 * And there must be a '[' in each meaning that it is a script-defined array type.
1015 */
1016 int i = srctypename.IndexOf ('[');
1017 int j = dsttypename.IndexOf ('[');
1018 if ((i < 0) || (j < 0)) throw new InvalidCastException ("non-array passed: " + srctypename + " and/or " + dsttypename);
1019 if ((i != j) || !srctypename.StartsWith (dsttypename.Substring (0, j))) {
1020 throw new ArrayTypeMismatchException (srctypename + " vs " + dsttypename);
1021 }
1022
1023 /*
1024 * The number of brackets must match exactly.
1025 * This permits copying from something like a float[,][] to something like a float[][].
1026 * But you cannot copy from a float[][] to a float[] or wisa wersa.
1027 * Counting either '[' or ']' would work equally well.
1028 */
1029 int srclen = srctypename.Length;
1030 int dstlen = dsttypename.Length;
1031 int srcjags = 0;
1032 int dstjags = 0;
1033 while (++ i < srclen) if (srctypename[i] == ']') srcjags ++;
1034 while (++ j < dstlen) if (dsttypename[j] == ']') dstjags ++;
1035 if (dstjags != srcjags) {
1036 throw new ArrayTypeMismatchException (srctypename + " vs " + dsttypename);
1037 }
1038
1039 /*
1040 * Perform the copy.
1041 */
1042 Array srcarray = (Array)srcsdt.instVars.iarObjects[0];
1043 Array dstarray = (Array)dstsdt.instVars.iarObjects[0];
1044 Array.Copy (srcarray, srcstart, dstarray, dststart, count);
1045 }
1046
1047 /**
1048 * @brief Copy from an array to a list.
1049 * @param srcar = the array to copy from
1050 * @param start = where to start in the array
1051 * @param count = number of elements
1052 * @returns the list
1053 */
1054 public static LSL_List xmrArray2List (object srcar, int start, int count)
1055 {
1056 /*
1057 * Get the script-visible type of the array.
1058 * We only do arrays.
1059 */
1060 XMRSDTypeClObj array = (XMRSDTypeClObj)srcar;
1061 TokenDeclSDTypeClass sdtClass = array.sdtcClass;
1062 if (sdtClass.arrayOfRank == 0) {
1063 throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
1064 }
1065
1066 /*
1067 * Validate objects they want to put in the list.
1068 * We can't allow anything funky that OpenSim runtime doesn't expect.
1069 */
1070 Array srcarray = (Array)array.instVars.iarObjects[0];
1071 object[] output = new object[count];
1072 for (int i = 0; i < count; i ++) {
1073 object src = srcarray.GetValue (i + start);
1074 if (src == null) throw new NullReferenceException ("null element " + i);
1075 if (src is double) {
1076 output[i] = new LSL_Float ((double)src);
1077 continue;
1078 }
1079 if (src is int) {
1080 output[i] = new LSL_Integer ((int)src);
1081 continue;
1082 }
1083 if (src is LSL_Rotation) {
1084 output[i] = src;
1085 continue;
1086 }
1087 if (src is LSL_Vector) {
1088 output[i] = src;
1089 continue;
1090 }
1091 if (src is string) {
1092 output[i] = new LSL_String ((string)src);
1093 continue;
1094 }
1095 throw new InvalidCastException ("invalid element " + i + " type " + src.GetType ().Name);
1096 }
1097
1098 /*
1099 * Make a list out of that now immutable array.
1100 */
1101 return new LSL_List (output);
1102 }
1103
1104 /**
1105 * @brief Copy from a list to an array.
1106 * @param srclist = list to copy from
1107 * @param srcstart = where to start in the list
1108 * @param dstobj = array to copy to
1109 * @param dststart = where to start in the array
1110 * @param count = number of elements
1111 */
1112 public static void xmrList2Array (LSL_List srclist, int srcstart, object dstobj, int dststart, int count)
1113 {
1114 /*
1115 * Get the script-visible type of the destination.
1116 * We only do arrays.
1117 */
1118 XMRSDTypeClObj dstarray = (XMRSDTypeClObj)dstobj;
1119 TokenDeclSDTypeClass sdtClass = dstarray.sdtcClass;
1120 if (sdtClass.arrayOfType == null) {
1121 throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
1122 }
1123
1124 /*
1125 * Copy from the immutable array to the mutable array.
1126 * Strip off any LSL wrappers as the script code doesn't expect any.
1127 */
1128 object[] srcarr = srclist.Data;
1129 Array dstarr = (Array)dstarray.instVars.iarObjects[0];
1130
1131 for (int i = 0; i < count; i ++) {
1132 object obj = srcarr[i+srcstart];
1133 if (obj is LSL_Float) obj = ((LSL_Float)obj).value;
1134 if (obj is LSL_Integer) obj = ((LSL_Integer)obj).value;
1135 if (obj is LSL_String) obj = ((LSL_String)obj).m_string;
1136 dstarr.SetValue (obj, i + dststart);
1137 }
1138 }
1139
1140 /**
1141 * @brief Copy from an array of characters to a string.
1142 * @param srcar = the array to copy from
1143 * @param start = where to start in the array
1144 * @param count = number of elements
1145 * @returns the string
1146 */
1147 public static string xmrChars2String (object srcar, int start, int count)
1148 {
1149 /*
1150 * Make sure they gave us a script-defined array object.
1151 */
1152 XMRSDTypeClObj array = (XMRSDTypeClObj)srcar;
1153 TokenDeclSDTypeClass sdtClass = array.sdtcClass;
1154 if (sdtClass.arrayOfRank == 0) {
1155 throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
1156 }
1157
1158 /*
1159 * We get a type cast error from mono if they didn't give us a character array.
1160 * But if it is ok, create a string from the requested characters.
1161 */
1162 char[] srcarray = (char[])array.instVars.iarObjects[0];
1163 return new string (srcarray, start, count);
1164 }
1165
1166 /**
1167 * @brief Copy from a string to a character array.
1168 * @param srcstr = string to copy from
1169 * @param srcstart = where to start in the string
1170 * @param dstobj = array to copy to
1171 * @param dststart = where to start in the array
1172 * @param count = number of elements
1173 */
1174 public static void xmrString2Chars (string srcstr, int srcstart, object dstobj, int dststart, int count)
1175 {
1176 /*
1177 * Make sure they gave us a script-defined array object.
1178 */
1179 XMRSDTypeClObj dstarray = (XMRSDTypeClObj)dstobj;
1180 TokenDeclSDTypeClass sdtClass = dstarray.sdtcClass;
1181 if (sdtClass.arrayOfType == null) {
1182 throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
1183 }
1184
1185 /*
1186 * We get a type cast error from mono if they didn't give us a character array.
1187 * But if it is ok, copy from the string to the character array.
1188 */
1189 char[] dstarr = (char[])dstarray.instVars.iarObjects[0];
1190 for (int i = 0; i < count; i ++) {
1191 dstarr[i+dststart] = srcstr[i+srcstart];
1192 }
1193 }
1194
1195 /**
1196 * @brief Implement osParseJSON() so we return an array to the script.
1197 * No coherent example of its use in scripts on web found.
1198 * see http://www.json.org/ for more details on JSON
1199 */
1200 private static LSL_List nullList = new LSL_List (new object[0]);
1201 public new XMR_Array osParseJSON (string json)
1202 {
1203 XMR_Array dict = new XMR_Array (this);
1204 int idx = ParseJSON (dict, nullList, json, 0);
1205 while (idx < json.Length) {
1206 if (json[idx] > ' ') throw new Exception ("left-over json " + json);
1207 idx ++;
1208 }
1209 return dict;
1210 }
1211
1212 private static int ParseJSON (XMR_Array dict, LSL_List keys, string json, int idx)
1213 {
1214 char c;
1215
1216 while ((c = json[idx++]) <= ' ') { }
1217 switch (c) {
1218
1219 // '{' <keystring> ':' <value> [ ',' <keystring> ':' <value> ... ] '}'
1220 case '{': {
1221 do {
1222 string key = ParseJSONString (json, ref idx);
1223 while ((c = json[idx++]) <= ' ') { }
1224 if (c != ':') throw new Exception ("missing : after key");
1225 idx = ParseJSON (dict, ParseJSONKeyAdd (keys, key), json, idx);
1226 while ((c = json[idx++]) <= ' ') { }
1227 } while (c == ',');
1228 if (c != '}') throw new Exception ("missing , or } after value");
1229 break;
1230 }
1231
1232 // '[' <value> [ ',' <value> ... ] ']'
1233 case '[': {
1234 int index = 0;
1235 do {
1236 object key = index ++;
1237 idx = ParseJSON (dict, ParseJSONKeyAdd (keys, key), json, idx);
1238 while ((c = json[idx++]) <= ' ') { }
1239 } while (c == ',');
1240 if (c != ']') throw new Exception ("missing , or ] after value");
1241 break;
1242 }
1243
1244 // '"'<string>'"'
1245 case '"': {
1246 -- idx;
1247 string val = ParseJSONString (json, ref idx);
1248 dict.SetByKey (keys, val);
1249 break;
1250 }
1251
1252 // true false null
1253 case 't': {
1254 if (json.Substring (idx, 3) != "rue") throw new Exception ("bad true in json");
1255 idx += 3;
1256 dict.SetByKey (keys, 1);
1257 break;
1258 }
1259
1260 case 'f': {
1261 if (json.Substring (idx, 4) != "alse") throw new Exception ("bad false in json");
1262 idx += 4;
1263 dict.SetByKey (keys, 0);
1264 break;
1265 }
1266
1267 case 'n': {
1268 if (json.Substring (idx, 3) != "ull") throw new Exception ("bad null in json");
1269 idx += 3;
1270 dict.SetByKey (keys, null);
1271 break;
1272 }
1273
1274 // otherwise assume it's a number
1275 default: {
1276 -- idx;
1277 object val = ParseJSONNumber (json, ref idx);
1278 dict.SetByKey (keys, val);
1279 break;
1280 }
1281 }
1282
1283 return idx;
1284 }
1285
1286 // Given the key for a whole array, create a key for a given element of the array
1287 private static LSL_List ParseJSONKeyAdd (LSL_List oldkeys, object key)
1288 {
1289 int oldkeyslen = oldkeys.Length;
1290 object[] array = oldkeys.Data;
1291 Array.Resize<object> (ref array, oldkeyslen + 1);
1292 array[oldkeyslen] = key;
1293 return new LSL_List (array);
1294 }
1295
1296 // Parse out a JSON string
1297 private static string ParseJSONString (string json, ref int idx)
1298 {
1299 char c;
1300
1301 while ((c = json[idx++]) <= ' ') { }
1302 if (c != '"') throw new Exception ("bad start of json string");
1303
1304 StringBuilder sb = new StringBuilder ();
1305 while ((c = json[idx++]) != '"') {
1306 if (c == '\\') {
1307 c = json[idx++];
1308 switch (c) {
1309 case 'b': {
1310 c = '\b';
1311 break;
1312 }
1313 case 'f': {
1314 c = '\f';
1315 break;
1316 }
1317 case 'n': {
1318 c = '\n';
1319 break;
1320 }
1321 case 'r': {
1322 c = '\r';
1323 break;
1324 }
1325 case 't': {
1326 c = '\t';
1327 break;
1328 }
1329 case 'u': {
1330 c = (char) Int32.Parse (json.Substring (idx, 4),
1331 System.Globalization.NumberStyles.HexNumber);
1332 idx += 4;
1333 break;
1334 }
1335 default: break;
1336 }
1337 }
1338 sb.Append (c);
1339 }
1340 return sb.ToString ();
1341 }
1342
1343 // Parse out a JSON number
1344 private static object ParseJSONNumber (string json, ref int idx)
1345 {
1346 char c;
1347
1348 while ((c = json[idx++]) <= ' ') { }
1349
1350 bool expneg = false;
1351 bool isneg = false;
1352 int decpt = -1;
1353 int expon = 0;
1354 int ival = 0;
1355 double dval = 0;
1356
1357 if (c == '-') {
1358 isneg = true;
1359 c = json[idx++];
1360 }
1361 if ((c < '0') || (c > '9')) {
1362 throw new Exception ("bad json number");
1363 }
1364 while ((c >= '0') && (c <= '9')) {
1365 dval *= 10;
1366 ival *= 10;
1367 dval += c - '0';
1368 ival += c - '0';
1369 c = '\0';
1370 if (idx < json.Length) c = json[idx++];
1371 }
1372 if (c == '.') {
1373 decpt = 0;
1374 c = '\0';
1375 if (idx < json.Length) c = json[idx++];
1376 while ((c >= '0') && (c <= '9')) {
1377 dval *= 10;
1378 dval += c - '0';
1379 decpt ++;
1380 c = '\0';
1381 if (idx < json.Length) c = json[idx++];
1382 }
1383 }
1384 if ((c == 'e') || (c == 'E')) {
1385 if (decpt < 0) decpt = 0;
1386 c = json[idx++];
1387 if (c == '-') expneg = true;
1388 if ((c == '-') || (c == '+')) c = json[idx++];
1389 while ((c >= '0') && (c <= '9')) {
1390 expon *= 10;
1391 expon += c - '0';
1392 c = '\0';
1393 if (idx < json.Length) c = json[idx++];
1394 }
1395 if (expneg) expon = -expon;
1396 }
1397
1398 if (c != 0) -- idx;
1399 if (decpt < 0) {
1400 if (isneg) ival = -ival;
1401 return ival;
1402 } else {
1403 if (isneg) dval = -dval;
1404 dval *= Math.Pow (10, expon - decpt);
1405 return dval;
1406 }
1407 }
1408
1409 /**
1410 * @brief Exception-related runtime calls.
1411 */
1412 // Return exception message (no type information just the message)
1413 public static string xmrExceptionMessage (Exception ex)
1414 {
1415 return ex.Message;
1416 }
1417
1418 // Return stack trace (no type or message, just stack trace lines: at ... \n)
1419 public string xmrExceptionStackTrace (Exception ex)
1420 {
1421 return XMRExceptionStackString (ex);
1422 }
1423
1424 // Return value thrown by a throw statement
1425 public static object xmrExceptionThrownValue (Exception ex)
1426 {
1427 return ((ScriptThrownException)ex).thrown;
1428 }
1429
1430 // Return exception's short type name, eg, NullReferenceException, ScriptThrownException, etc.
1431 public static string xmrExceptionTypeName (Exception ex)
1432 {
1433 return ex.GetType ().Name;
1434 }
1435
1436 // internal use only: converts any IL addresses in script-defined methods to source location equivalent
1437 // at (wrapper dynamic-method) object.__seh_0_30_default_state_entry (OpenSim.Region.ScriptEngine.XMREngine.XMRInstAbstract) <IL 0x00d65, 0x03a53>
1438 public string XMRExceptionStackString (Exception ex)
1439 {
1440 string st = ex.StackTrace;
1441 StringBuilder sb = new StringBuilder ();
1442 int wrapDynMethObj = 0;
1443 int leftOffAt = 0;
1444 while ((wrapDynMethObj = st.IndexOf ("(wrapper dynamic-method) System.Object:", ++ wrapDynMethObj)) >= 0) {
1445 try {
1446 int begFuncName = wrapDynMethObj + 39;
1447 int endFuncName = st.IndexOf (" (", begFuncName);
1448 string funcName = st.Substring (begFuncName, endFuncName - begFuncName);
1449 KeyValuePair<int, ScriptSrcLoc>[] srcLocs = m_ObjCode.scriptSrcLocss[funcName];
1450
1451 int il0xPrefix = st.IndexOf (" [0x", endFuncName);
1452 int begILHex = il0xPrefix + 4;
1453 int endILHex = st.IndexOf (']', begILHex);
1454 string ilHex = st.Substring (begILHex, endILHex - begILHex);
1455 int offset = Int32.Parse (ilHex, System.Globalization.NumberStyles.HexNumber);
1456
1457 int srcLocIdx;
1458 int srcLocLen = srcLocs.Length;
1459 for (srcLocIdx = 0; ++ srcLocIdx < srcLocLen;) {
1460 if (offset < srcLocs[srcLocIdx].Key) break;
1461 }
1462 ScriptSrcLoc srcLoc = srcLocs[--srcLocIdx].Value;
1463
1464 sb.Append (st.Substring (leftOffAt, wrapDynMethObj - leftOffAt));
1465 sb.Append (st.Substring (begFuncName, endFuncName - begFuncName));
1466 sb.Append (" <");
1467 sb.Append (srcLoc.file);
1468 sb.Append ('(');
1469 sb.Append (srcLoc.line);
1470 sb.Append (',');
1471 sb.Append (srcLoc.posn);
1472 sb.Append (")>");
1473
1474 leftOffAt = ++ endILHex;
1475 } catch {
1476 }
1477 }
1478 sb.Append (st.Substring (leftOffAt));
1479 return sb.ToString ();
1480 }
1481
1482 /**
1483 * @brief List fonts available.
1484 */
1485 public LSL_List xmrFontsAvailable ()
1486 {
1487 System.Drawing.FontFamily[] families = System.Drawing.FontFamily.Families;
1488 object[] output = new object[families.Length];
1489 for (int i = 0; i < families.Length; i ++) {
1490 output[i] = new LSL_String (families[i].Name);
1491 }
1492 return new LSL_List (output);
1493 }
1494
1495 /************************\
1496 * Used by decompiler *
1497 \************************/
1498
1499 public bool xmrRotationToBool (LSL_Rotation x) { return TypeCast.RotationToBool (x); }
1500 public bool xmrStringToBool (string x) { return TypeCast.StringToBool (x); }
1501 public bool xmrVectorToBool (LSL_Vector x) { return TypeCast.VectorToBool (x); }
1502 public bool xmrKeyToBool (string x) { return TypeCast.KeyToBool (x); }
1503 public bool xmrListToBool (LSL_List x) { return TypeCast.ListToBool (x); }
1504
1505 public int xmrStringCompare (string x, string y) { return string.Compare (x, y); }
1506
1507 /**
1508 * @brief types of data we serialize
1509 */
1510 private enum Ser : byte {
1511 NULL,
1512 EVENTCODE,
1513 LSLFLOAT,
1514 LSLINT,
1515 LSLKEY,
1516 LSLLIST,
1517 LSLROT,
1518 LSLSTR,
1519 LSLVEC,
1520 SYSARRAY,
1521 SYSDOUB,
1522 SYSFLOAT,
1523 SYSINT,
1524 SYSSTR,
1525 XMRARRAY,
1526 DUPREF,
1527 SYSBOOL,
1528 XMRINST,
1529 DELEGATE,
1530 SDTCLOBJ,
1531 SYSCHAR,
1532 SYSERIAL,
1533 THROWNEX
1534 }
1535
1536 /**
1537 * @brief Write state out to a stream.
1538 * Do not change script state.
1539 */
1540 public void MigrateOut (BinaryWriter mow)
1541 {
1542 try {
1543 this.migrateOutWriter = mow;
1544 this.migrateOutObjects = new Dictionary<object,int> ();
1545 this.migrateOutLists = new Dictionary<object[],ObjLslList> ();
1546 this.SendObjValue (this.ehArgs);
1547 mow.Write (this.doGblInit);
1548 mow.Write (this.stateCode);
1549 mow.Write ((int)this.eventCode);
1550 this.glblVars.SendArrays (this.SendObjValue);
1551 if (this.newStateCode >= 0) {
1552 mow.Write ("**newStateCode**");
1553 mow.Write (this.newStateCode);
1554 }
1555 for (XMRStackFrame thisSF = this.stackFrames; thisSF != null; thisSF = thisSF.nextSF) {
1556 mow.Write (thisSF.funcName);
1557 mow.Write (thisSF.callNo);
1558 this.SendObjValue (thisSF.objArray);
1559 }
1560 mow.Write ("");
1561 } finally {
1562 this.migrateOutWriter = null;
1563 this.migrateOutObjects = null;
1564 this.migrateOutLists = null;
1565 }
1566 }
1567
1568 /**
1569 * @brief Write an object to the output stream.
1570 * @param graph = object to send
1571 */
1572 private BinaryWriter migrateOutWriter;
1573 private Dictionary<object,int> migrateOutObjects;
1574 private Dictionary<object[],ObjLslList> migrateOutLists;
1575 public void SendObjValue (object graph)
1576 {
1577 BinaryWriter mow = this.migrateOutWriter;
1578
1579 /*
1580 * Value types (including nulls) are always output directly.
1581 */
1582 if (graph == null) {
1583 mow.Write ((byte)Ser.NULL);
1584 return;
1585 }
1586 if (graph is ScriptEventCode) {
1587 mow.Write ((byte)Ser.EVENTCODE);
1588 mow.Write ((int)graph);
1589 return;
1590 }
1591 if (graph is LSL_Float) {
1592 mow.Write ((byte)Ser.LSLFLOAT);
1593 mow.Write ((double)((LSL_Float)graph).value);
1594 return;
1595 }
1596 if (graph is LSL_Integer) {
1597 mow.Write ((byte)Ser.LSLINT);
1598 mow.Write ((int)((LSL_Integer)graph).value);
1599 return;
1600 }
1601 if (graph is LSL_Key) {
1602 mow.Write ((byte)Ser.LSLKEY);
1603 LSL_Key key = (LSL_Key)graph;
1604 SendObjValue (key.m_string); // m_string can be null
1605 return;
1606 }
1607 if (graph is LSL_Rotation) {
1608 mow.Write ((byte)Ser.LSLROT);
1609 mow.Write ((double)((LSL_Rotation)graph).x);
1610 mow.Write ((double)((LSL_Rotation)graph).y);
1611 mow.Write ((double)((LSL_Rotation)graph).z);
1612 mow.Write ((double)((LSL_Rotation)graph).s);
1613 return;
1614 }
1615 if (graph is LSL_String) {
1616 mow.Write ((byte)Ser.LSLSTR);
1617 LSL_String str = (LSL_String)graph;
1618 SendObjValue (str.m_string); // m_string can be null
1619 return;
1620 }
1621 if (graph is LSL_Vector) {
1622 mow.Write ((byte)Ser.LSLVEC);
1623 mow.Write ((double)((LSL_Vector)graph).x);
1624 mow.Write ((double)((LSL_Vector)graph).y);
1625 mow.Write ((double)((LSL_Vector)graph).z);
1626 return;
1627 }
1628 if (graph is bool) {
1629 mow.Write ((byte)Ser.SYSBOOL);
1630 mow.Write ((bool)graph);
1631 return;
1632 }
1633 if (graph is double) {
1634 mow.Write ((byte)Ser.SYSDOUB);
1635 mow.Write ((double)graph);
1636 return;
1637 }
1638 if (graph is float) {
1639 mow.Write ((byte)Ser.SYSFLOAT);
1640 mow.Write ((float)graph);
1641 return;
1642 }
1643 if (graph is int) {
1644 mow.Write ((byte)Ser.SYSINT);
1645 mow.Write ((int)graph);
1646 return;
1647 }
1648 if (graph is char) {
1649 mow.Write ((byte)Ser.SYSCHAR);
1650 mow.Write ((char)graph);
1651 return;
1652 }
1653
1654 /*
1655 * Script instance pointer is always just that.
1656 */
1657 if (graph == this) {
1658 mow.Write ((byte)Ser.XMRINST);
1659 return;
1660 }
1661
1662 /*
1663 * Convert lists to object type.
1664 * This is compatible with old migration data and also
1665 * two vars pointing to same list won't duplicate it.
1666 */
1667 if (graph is LSL_List) {
1668 object[] data = ((LSL_List) graph).Data;
1669 ObjLslList oll;
1670 if (!this.migrateOutLists.TryGetValue (data, out oll)) {
1671 oll = new ObjLslList ();
1672 oll.objarray = data;
1673 this.migrateOutLists[data] = oll;
1674 }
1675 graph = oll;
1676 }
1677
1678 /*
1679 * If this same exact object was already serialized,
1680 * just output an index telling the receiver to use
1681 * that same old object, rather than creating a whole
1682 * new object with the same values. Also this prevents
1683 * self-referencing objects (like arrays) from causing
1684 * an infinite loop.
1685 */
1686 int ident;
1687 if (this.migrateOutObjects.TryGetValue (graph, out ident)) {
1688 mow.Write ((byte)Ser.DUPREF);
1689 mow.Write (ident);
1690 return;
1691 }
1692
1693 /*
1694 * Object not seen before, save its address with an unique
1695 * ident number that the receiver can easily regenerate.
1696 */
1697 ident = this.migrateOutObjects.Count;
1698 this.migrateOutObjects.Add (graph, ident);
1699
1700 /*
1701 * Now output the object's value(s).
1702 * If the object self-references, the object is alreay entered
1703 * in the dictionary and so the self-reference will just emit
1704 * a DUPREF tag instead of trying to output the whole object
1705 * again.
1706 */
1707 if (graph is ObjLslList) {
1708 mow.Write ((byte)Ser.LSLLIST);
1709 ObjLslList oll = (ObjLslList) graph;
1710 SendObjValue (oll.objarray);
1711 } else if (graph is XMR_Array) {
1712 mow.Write ((byte)Ser.XMRARRAY);
1713 ((XMR_Array)graph).SendArrayObj (this.SendObjValue);
1714 } else if (graph is Array) {
1715 Array array = (Array)graph;
1716 mow.Write ((byte)Ser.SYSARRAY);
1717 mow.Write (SysType2String (array.GetType ().GetElementType ()));
1718 mow.Write ((int)array.Length);
1719 for (int i = 0; i < array.Length; i ++) {
1720 this.SendObjValue (array.GetValue (i));
1721 }
1722 } else if (graph is string) {
1723 mow.Write ((byte)Ser.SYSSTR);
1724 mow.Write ((string)graph);
1725 } else if (graph is Delegate) {
1726 Delegate del = (Delegate)graph;
1727 mow.Write ((byte)Ser.DELEGATE);
1728 mow.Write (del.Method.Name);
1729 Type delType = del.GetType ();
1730 foreach (KeyValuePair<string, TokenDeclSDType> kvp in m_ObjCode.sdObjTypesName) {
1731 TokenDeclSDType sdt = kvp.Value;
1732 if (sdt is TokenDeclSDTypeDelegate) {
1733 TokenDeclSDTypeDelegate sdtd = (TokenDeclSDTypeDelegate)sdt;
1734 if (sdtd.GetSysType () == delType) {
1735 mow.Write (kvp.Key);
1736 goto found;
1737 }
1738 }
1739 }
1740 throw new Exception ("cant find script-defined delegate for " + del.Method.Name + " type " + del.GetType ());
1741 found:
1742 SendObjValue (del.Target);
1743 } else if (graph is XMRSDTypeClObj) {
1744 mow.Write ((byte)Ser.SDTCLOBJ);
1745 ((XMRSDTypeClObj)graph).Capture (this.SendObjValue);
1746 } else if (graph is ScriptThrownException) {
1747 MemoryStream memoryStream = new MemoryStream ();
1748 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
1749 new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
1750 bformatter.Serialize (memoryStream, graph);
1751 byte[] rawBytes = memoryStream.ToArray ();
1752 mow.Write ((byte)Ser.THROWNEX);
1753 mow.Write ((int)rawBytes.Length);
1754 mow.Write (rawBytes);
1755 SendObjValue (((ScriptThrownException)graph).thrown);
1756 } else {
1757 MemoryStream memoryStream = new MemoryStream ();
1758 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
1759 new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
1760 bformatter.Serialize (memoryStream, graph);
1761 byte[] rawBytes = memoryStream.ToArray ();
1762 mow.Write ((byte)Ser.SYSERIAL);
1763 mow.Write ((int)rawBytes.Length);
1764 mow.Write (rawBytes);
1765 }
1766 }
1767
1768 /**
1769 * @brief Use short strings for known type names.
1770 */
1771 private static string SysType2String (Type type)
1772 {
1773 if (type.IsArray && (type.GetArrayRank () == 1)) {
1774 string str = KnownSysType2String (type.GetElementType ());
1775 if (str != null) return str + "[]";
1776 } else {
1777 string str = KnownSysType2String (type);
1778 if (str != null) return str;
1779 }
1780 return type.ToString ();
1781 }
1782 private static string KnownSysType2String (Type type)
1783 {
1784 if (type == typeof (bool)) return "bo";
1785 if (type == typeof (char)) return "ch";
1786 if (type == typeof (Delegate)) return "de";
1787 if (type == typeof (double)) return "do";
1788 if (type == typeof (float)) return "fl";
1789 if (type == typeof (int)) return "in";
1790 if (type == typeof (LSL_List)) return "li";
1791 if (type == typeof (object)) return "ob";
1792 if (type == typeof (LSL_Rotation)) return "ro";
1793 if (type == typeof (XMRSDTypeClObj)) return "sc";
1794 if (type == typeof (string)) return "st";
1795 if (type == typeof (LSL_Vector)) return "ve";
1796 if (type == typeof (XMR_Array)) return "xa";
1797 return null;
1798 }
1799 private static Type String2SysType (string str)
1800 {
1801 if (str.EndsWith ("[]")) {
1802 return String2SysType (str.Substring (0, str.Length - 2)).MakeArrayType ();
1803 }
1804 if (str == "bo") return typeof (bool);
1805 if (str == "ch") return typeof (char);
1806 if (str == "de") return typeof (Delegate);
1807 if (str == "do") return typeof (double);
1808 if (str == "fl") return typeof (float);
1809 if (str == "in") return typeof (int);
1810 if (str == "li") return typeof (LSL_List);
1811 if (str == "ob") return typeof (object);
1812 if (str == "ro") return typeof (LSL_Rotation);
1813 if (str == "sc") return typeof (XMRSDTypeClObj);
1814 if (str == "st") return typeof (string);
1815 if (str == "ve") return typeof (LSL_Vector);
1816 if (str == "xa") return typeof (XMR_Array);
1817 return Type.GetType (str, true);
1818 }
1819
1820 /**
1821 * @brief Read state in from a stream.
1822 */
1823 public void MigrateIn (BinaryReader mir)
1824 {
1825 try {
1826 this.migrateInReader = mir;
1827 this.migrateInObjects = new Dictionary<int, object> ();
1828 this.ehArgs = (object[])this.RecvObjValue ();
1829 this.doGblInit = mir.ReadBoolean ();
1830 this.stateCode = mir.ReadInt32 ();
1831 this.eventCode = (ScriptEventCode)mir.ReadInt32 ();
1832 this.newStateCode = -1;
1833 this.glblVars.RecvArrays (this.RecvObjValue);
1834 XMRStackFrame lastSF = null;
1835 string funcName;
1836 while ((funcName = mir.ReadString ()) != "") {
1837 if (funcName == "**newStateCode**") {
1838 this.newStateCode = mir.ReadInt32 ();
1839 continue;
1840 }
1841 XMRStackFrame thisSF = new XMRStackFrame ();
1842 thisSF.funcName = funcName;
1843 thisSF.callNo = mir.ReadInt32 ();
1844 thisSF.objArray = (object[])this.RecvObjValue ();
1845 if (lastSF == null) this.stackFrames = thisSF;
1846 else lastSF.nextSF = thisSF;
1847 lastSF = thisSF;
1848 }
1849 } finally {
1850 this.migrateInReader = null;
1851 this.migrateInObjects = null;
1852 }
1853 }
1854
1855 /**
1856 * @brief Read a single value from the stream.
1857 * @returns value (boxed as needed)
1858 */
1859 private BinaryReader migrateInReader;
1860 private Dictionary<int, object> migrateInObjects;
1861 public object RecvObjValue ()
1862 {
1863 BinaryReader mir = this.migrateInReader;
1864 int ident = this.migrateInObjects.Count;
1865 Ser code = (Ser)mir.ReadByte ();
1866 switch (code) {
1867 case Ser.NULL: {
1868 return null;
1869 }
1870 case Ser.EVENTCODE: {
1871 return (ScriptEventCode)mir.ReadInt32 ();
1872 }
1873 case Ser.LSLFLOAT: {
1874 return new LSL_Float (mir.ReadDouble ());
1875 }
1876 case Ser.LSLINT: {
1877 return new LSL_Integer (mir.ReadInt32 ());
1878 }
1879 case Ser.LSLKEY: {
1880 return new LSL_Key ((string)RecvObjValue ());
1881 }
1882 case Ser.LSLLIST: {
1883 this.migrateInObjects.Add (ident, null); // placeholder
1884 object[] data = (object[])RecvObjValue (); // read data, maybe using another index
1885 LSL_List list = new LSL_List (data); // make LSL-level list
1886 this.migrateInObjects[ident] = list; // fill in slot
1887 return list;
1888 }
1889 case Ser.LSLROT: {
1890 double x = mir.ReadDouble ();
1891 double y = mir.ReadDouble ();
1892 double z = mir.ReadDouble ();
1893 double s = mir.ReadDouble ();
1894 return new LSL_Rotation (x, y, z, s);
1895 }
1896 case Ser.LSLSTR: {
1897 return new LSL_String ((string)RecvObjValue ());
1898 }
1899 case Ser.LSLVEC: {
1900 double x = mir.ReadDouble ();
1901 double y = mir.ReadDouble ();
1902 double z = mir.ReadDouble ();
1903 return new LSL_Vector (x, y, z);
1904 }
1905 case Ser.SYSARRAY: {
1906 Type eletype = String2SysType (mir.ReadString ());
1907 int length = mir.ReadInt32 ();
1908 Array array = Array.CreateInstance (eletype, length);
1909 this.migrateInObjects.Add (ident, array);
1910 for (int i = 0; i < length; i ++) {
1911 array.SetValue (RecvObjValue (), i);
1912 }
1913 return array;
1914 }
1915 case Ser.SYSBOOL: {
1916 return mir.ReadBoolean ();
1917 }
1918 case Ser.SYSDOUB: {
1919 return mir.ReadDouble ();
1920 }
1921 case Ser.SYSFLOAT: {
1922 return mir.ReadSingle ();
1923 }
1924 case Ser.SYSINT: {
1925 return mir.ReadInt32 ();
1926 }
1927 case Ser.SYSCHAR: {
1928 return mir.ReadChar ();
1929 }
1930 case Ser.SYSSTR: {
1931 string s = mir.ReadString ();
1932 this.migrateInObjects.Add (ident, s);
1933 return s;
1934 }
1935 case Ser.XMRARRAY: {
1936 XMR_Array array = new XMR_Array (this);
1937 this.migrateInObjects.Add (ident, array);
1938 array.RecvArrayObj (this.RecvObjValue);
1939 return array;
1940 }
1941 case Ser.DUPREF: {
1942 ident = mir.ReadInt32 ();
1943 object obj = this.migrateInObjects[ident];
1944 if (obj is ObjLslList) obj = new LSL_List (((ObjLslList) obj).objarray);
1945 return obj;
1946 }
1947 case Ser.XMRINST: {
1948 return this;
1949 }
1950 case Ser.DELEGATE: {
1951 this.migrateInObjects.Add (ident, null); // placeholder
1952 string name = mir.ReadString (); // function name
1953 string sig = mir.ReadString (); // delegate type
1954 object targ = this.RecvObjValue (); // 'this' object
1955 Delegate del = this.GetScriptMethodDelegate (name, sig, targ);
1956 this.migrateInObjects[ident] = del; // actual value
1957 return del;
1958 }
1959 case Ser.SDTCLOBJ: {
1960 XMRSDTypeClObj clobj = new XMRSDTypeClObj ();
1961 this.migrateInObjects.Add (ident, clobj);
1962 clobj.Restore (this, this.RecvObjValue);
1963 return clobj;
1964 }
1965 case Ser.SYSERIAL: {
1966 int rawLength = mir.ReadInt32 ();
1967 byte[] rawBytes = mir.ReadBytes (rawLength);
1968 MemoryStream memoryStream = new MemoryStream (rawBytes);
1969 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
1970 new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
1971 object graph = bformatter.Deserialize (memoryStream);
1972 this.migrateInObjects.Add (ident, graph);
1973 return graph;
1974 }
1975 case Ser.THROWNEX: {
1976 int rawLength = mir.ReadInt32 ();
1977 byte[] rawBytes = mir.ReadBytes (rawLength);
1978 MemoryStream memoryStream = new MemoryStream (rawBytes);
1979 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
1980 new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
1981 object graph = bformatter.Deserialize (memoryStream);
1982 this.migrateInObjects.Add (ident, graph);
1983 ((ScriptThrownException)graph).thrown = RecvObjValue ();
1984 return graph;
1985 }
1986 default: throw new Exception ("bad stream code " + code.ToString ());
1987 }
1988 }
1989
1990 // wrapper around list object arrays to make sure they are always object types for migration purposes
1991 private class ObjLslList {
1992 public object[] objarray;
1993 }
1994 }
1995
1996 /**
1997 * @brief Common access to script microthread.
1998 */
1999 public interface IScriptUThread : IDisposable
2000 {
2001 Exception ResumeEx (); // called by macrothread to resume execution at most recent Hiber()
2002 Exception StartEx (); // called by macrothread to start execution at CallSEH()
2003 int Active (); // called by macrothread to query state of microthread
2004 int StackLeft (); // called by microthread to query amount of remaining stack space
2005 void Hiber (); // called by microthread to hibernate
2006 }
2007
2008 // Any xmr...() methods that call CheckRun() must be tagged with this attribute
2009 // so the ScriptCodeGen will know the method is non-trivial.
2010 public class xmrMethodCallsCheckRunAttribute : Attribute { }
2011
2012 // Any xmr...() methods in xmrengtest that call Stub<somethingorother>() must be
2013 // tagged with this attribute so the -builtins option will tell the user that
2014 // they are a stub function.
2015 public class xmrMethodIsNoisyAttribute : Attribute { }
2016
2017 // Any script callable methods that really return a key not a string should be
2018 // tagged with this attribute so the compiler will know they return type key and
2019 // not type string.
2020 public class xmrMethodReturnsKeyAttribute : Attribute { }
2021
2022 [SerializableAttribute]
2023 public class OutOfHeapException : Exception {
2024 public OutOfHeapException (int oldtotal, int newtotal, int limit)
2025 : base ("oldtotal=" + oldtotal + ", newtotal=" + newtotal + ", limit=" + limit)
2026 { }
2027 }
2028
2029 [SerializableAttribute]
2030 public class OutOfStackException : Exception { }
2031}