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