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