729 lines
34 KiB
C#
729 lines
34 KiB
C#
/*
|
|
* Copyright (c) Contributors, http://opensimulator.org/
|
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the OpenSim Project nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
/* Original code: Tedd Hansen */
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Text;
|
|
using OpenSim.Region.ScriptEngine.LSOEngine.LSO;
|
|
|
|
namespace OpenSim.Region.ScriptEngine.LSOEngine.LSO
|
|
{
|
|
internal partial class LSO_Parser
|
|
{
|
|
private string FileName;
|
|
private FileStream fs;
|
|
private BinaryReader br;
|
|
internal LSO_Struct.Header myHeader;
|
|
internal Dictionary<long, LSO_Struct.StaticBlock> StaticBlocks = new Dictionary<long, LSO_Struct.StaticBlock>();
|
|
//private System.Collections.Hashtable StaticBlocks = new System.Collections.Hashtable();
|
|
|
|
private TypeBuilder typeBuilder;
|
|
private List<string> EventList = new List<string>();
|
|
|
|
public LSO_Parser(string _FileName, TypeBuilder _typeBuilder)
|
|
{
|
|
FileName = _FileName;
|
|
typeBuilder = _typeBuilder;
|
|
}
|
|
|
|
internal void OpenFile()
|
|
{
|
|
// Open
|
|
Common.SendToDebug("Opening filename: " + FileName);
|
|
fs = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
br = new BinaryReader(fs, Encoding.BigEndianUnicode);
|
|
}
|
|
|
|
internal void CloseFile()
|
|
{
|
|
// Close
|
|
br.Close();
|
|
fs.Close();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Parse LSO file.
|
|
/// </summary>
|
|
public void Parse()
|
|
{
|
|
// The LSO Format consist of 6 major blocks: header, statics, functions, states, heap, and stack.
|
|
|
|
|
|
// HEADER BLOCK
|
|
Common.SendToDebug("Reading HEADER BLOCK at: 0");
|
|
fs.Seek(0, SeekOrigin.Begin);
|
|
myHeader = new LSO_Struct.Header();
|
|
myHeader.TM = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.IP = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.VN = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.BP = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.SP = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.HR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.HP = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.CS = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.NS = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.CE = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.IE = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.ER = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.FR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.SLR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.GVR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.GFR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.PR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.ESR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.SR = BitConverter.ToUInt32(br_read(4), 0);
|
|
myHeader.NCE = BitConverter.ToUInt64(br_read(8), 0);
|
|
myHeader.NIE = BitConverter.ToUInt64(br_read(8), 0);
|
|
myHeader.NER = BitConverter.ToUInt64(br_read(8), 0);
|
|
|
|
// Print Header Block to debug
|
|
Common.SendToDebug("TM - Top of memory (size): " + myHeader.TM);
|
|
Common.SendToDebug("IP - Instruction Pointer (0=not running): " + myHeader.IP);
|
|
Common.SendToDebug("VN - Version number: " + myHeader.VN);
|
|
Common.SendToDebug("BP - Local Frame Pointer: " + myHeader.BP);
|
|
Common.SendToDebug("SP - Stack Pointer: " + myHeader.SP);
|
|
Common.SendToDebug("HR - Heap Register: " + myHeader.HR);
|
|
Common.SendToDebug("HP - Heap Pointer: " + myHeader.HP);
|
|
Common.SendToDebug("CS - Current State: " + myHeader.CS);
|
|
Common.SendToDebug("NS - Next State: " + myHeader.NS);
|
|
Common.SendToDebug("CE - Current Events: " + myHeader.CE);
|
|
Common.SendToDebug("IE - In Event: " + myHeader.IE);
|
|
Common.SendToDebug("ER - Event Register: " + myHeader.ER);
|
|
Common.SendToDebug("FR - Fault Register: " + myHeader.FR);
|
|
Common.SendToDebug("SLR - Sleep Register: " + myHeader.SLR);
|
|
Common.SendToDebug("GVR - Global Variable Register: " + myHeader.GVR);
|
|
Common.SendToDebug("GFR - Global Function Register: " + myHeader.GFR);
|
|
Common.SendToDebug("PR - Parameter Register: " + myHeader.PR);
|
|
Common.SendToDebug("ESR - Energy Supply Register: " + myHeader.ESR);
|
|
Common.SendToDebug("SR - State Register: " + myHeader.SR);
|
|
Common.SendToDebug("NCE - 64-bit Current Events: " + myHeader.NCE);
|
|
Common.SendToDebug("NIE - 64-bit In Events: " + myHeader.NIE);
|
|
Common.SendToDebug("NER - 64-bit Event Register: " + myHeader.NER);
|
|
Common.SendToDebug("Read position when exiting HEADER BLOCK: " + fs.Position);
|
|
|
|
// STATIC BLOCK
|
|
Common.SendToDebug("Reading STATIC BLOCK at: " + myHeader.GVR);
|
|
fs.Seek(myHeader.GVR, SeekOrigin.Begin);
|
|
int StaticBlockCount = 0;
|
|
// Read function blocks until we hit GFR
|
|
while (fs.Position < myHeader.GFR)
|
|
{
|
|
StaticBlockCount++;
|
|
long startReadPos = fs.Position;
|
|
Common.SendToDebug("Reading Static Block " + StaticBlockCount + " at: " + startReadPos);
|
|
|
|
//fs.Seek(myHeader.GVR, SeekOrigin.Begin);
|
|
LSO_Struct.StaticBlock myStaticBlock = new LSO_Struct.StaticBlock();
|
|
myStaticBlock.Static_Chunk_Header_Size = BitConverter.ToUInt32(br_read(4), 0);
|
|
myStaticBlock.ObjectType = br_read(1)[0];
|
|
Common.SendToDebug("Static Block ObjectType: " +
|
|
((LSO_Enums.Variable_Type_Codes) myStaticBlock.ObjectType).ToString());
|
|
myStaticBlock.Unknown = br_read(1)[0];
|
|
// Size of datatype varies -- what about strings?
|
|
if (myStaticBlock.ObjectType != 0)
|
|
myStaticBlock.BlockVariable = br_read(getObjectSize(myStaticBlock.ObjectType));
|
|
|
|
StaticBlocks.Add((UInt32) startReadPos, myStaticBlock);
|
|
}
|
|
Common.SendToDebug("Number of Static Blocks read: " + StaticBlockCount);
|
|
|
|
|
|
// FUNCTION BLOCK
|
|
// Always right after STATIC BLOCK
|
|
LSO_Struct.FunctionBlock myFunctionBlock = new LSO_Struct.FunctionBlock();
|
|
if (myHeader.GFR == myHeader.SR)
|
|
{
|
|
// If GFR and SR are at same position then there is no fuction block
|
|
Common.SendToDebug("No FUNCTION BLOCK found");
|
|
}
|
|
else
|
|
{
|
|
Common.SendToDebug("Reading FUNCTION BLOCK at: " + myHeader.GFR);
|
|
fs.Seek(myHeader.GFR, SeekOrigin.Begin);
|
|
myFunctionBlock.FunctionCount = BitConverter.ToUInt32(br_read(4), 0);
|
|
Common.SendToDebug("Number of functions in Fuction Block: " + myFunctionBlock.FunctionCount);
|
|
if (myFunctionBlock.FunctionCount > 0)
|
|
{
|
|
myFunctionBlock.CodeChunkPointer = new UInt32[myFunctionBlock.FunctionCount];
|
|
for (int i = 0; i < myFunctionBlock.FunctionCount; i++)
|
|
{
|
|
Common.SendToDebug("Reading function " + i + " at: " + fs.Position);
|
|
// TODO: ADD TO FUNCTION LIST (How do we identify it later?)
|
|
// Note! Absolute position
|
|
myFunctionBlock.CodeChunkPointer[i] = BitConverter.ToUInt32(br_read(4), 0) + myHeader.GFR;
|
|
Common.SendToDebug("Fuction " + i + " code chunk position: " +
|
|
myFunctionBlock.CodeChunkPointer[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// STATE FRAME BLOCK
|
|
// Always right after FUNCTION BLOCK
|
|
Common.SendToDebug("Reading STATE BLOCK at: " + myHeader.SR);
|
|
fs.Seek(myHeader.SR, SeekOrigin.Begin);
|
|
LSO_Struct.StateFrameBlock myStateFrameBlock = new LSO_Struct.StateFrameBlock();
|
|
myStateFrameBlock.StateCount = BitConverter.ToUInt32(br_read(4), 0);
|
|
if (myStateFrameBlock.StateCount > 0)
|
|
{
|
|
// Initialize array
|
|
myStateFrameBlock.StatePointer = new LSO_Struct.StatePointerBlock[myStateFrameBlock.StateCount];
|
|
for (int i = 0; i < myStateFrameBlock.StateCount; i++)
|
|
{
|
|
Common.SendToDebug("Reading STATE POINTER BLOCK " + (i + 1) + " at: " + fs.Position);
|
|
// Position is relative to state frame
|
|
myStateFrameBlock.StatePointer[i].Location = myHeader.SR + BitConverter.ToUInt32(br_read(4), 0);
|
|
myStateFrameBlock.StatePointer[i].EventMask = new BitArray(br_read(8));
|
|
Common.SendToDebug("Pointer: " + myStateFrameBlock.StatePointer[i].Location);
|
|
Common.SendToDebug("Total potential EventMask bits: " +
|
|
myStateFrameBlock.StatePointer[i].EventMask.Count);
|
|
|
|
//// Read STATE BLOCK
|
|
//long CurPos = fs.Position;
|
|
//fs.Seek(CurPos, SeekOrigin.Begin);
|
|
}
|
|
}
|
|
|
|
|
|
// STATE BLOCK
|
|
// For each StateFrameBlock there is one StateBlock with multiple event handlers
|
|
|
|
if (myStateFrameBlock.StateCount > 0)
|
|
{
|
|
// Go through all State Frame Pointers found
|
|
for (int i = 0; i < myStateFrameBlock.StateCount; i++)
|
|
{
|
|
fs.Seek(myStateFrameBlock.StatePointer[i].Location, SeekOrigin.Begin);
|
|
Common.SendToDebug("Reading STATE BLOCK " + (i + 1) + " at: " + fs.Position);
|
|
|
|
// READ: STATE BLOCK HEADER
|
|
myStateFrameBlock.StatePointer[i].StateBlock = new LSO_Struct.StateBlock();
|
|
myStateFrameBlock.StatePointer[i].StateBlock.StartPos = (UInt32) fs.Position; // Note
|
|
myStateFrameBlock.StatePointer[i].StateBlock.HeaderSize = BitConverter.ToUInt32(br_read(4), 0);
|
|
myStateFrameBlock.StatePointer[i].StateBlock.Unknown = br_read(1)[0];
|
|
myStateFrameBlock.StatePointer[i].StateBlock.EndPos = (UInt32) fs.Position; // Note
|
|
Common.SendToDebug("State block Start Pos: " + myStateFrameBlock.StatePointer[i].StateBlock.StartPos);
|
|
Common.SendToDebug("State block Header Size: " +
|
|
myStateFrameBlock.StatePointer[i].StateBlock.HeaderSize);
|
|
Common.SendToDebug("State block Header End Pos: " +
|
|
myStateFrameBlock.StatePointer[i].StateBlock.EndPos);
|
|
|
|
// We need to count number of bits flagged in EventMask?
|
|
|
|
|
|
// for each bit in myStateFrameBlock.StatePointer[i].EventMask
|
|
|
|
// ADDING TO ALL RIGHT NOW, SHOULD LIMIT TO ONLY THE ONES IN USE
|
|
//TODO: Create event hooks
|
|
myStateFrameBlock.StatePointer[i].StateBlock.StateBlockHandlers =
|
|
new LSO_Struct.StateBlockHandler[myStateFrameBlock.StatePointer[i].EventMask.Count - 1];
|
|
for (int ii = 0; ii < myStateFrameBlock.StatePointer[i].EventMask.Count - 1; ii++)
|
|
{
|
|
if (myStateFrameBlock.StatePointer[i].EventMask.Get(ii) == true)
|
|
{
|
|
// We got an event
|
|
// READ: STATE BLOCK HANDLER
|
|
Common.SendToDebug("Reading STATE BLOCK " + (i + 1) + " HANDLER matching EVENT MASK " + ii +
|
|
" (" + ((LSO_Enums.Event_Mask_Values) ii).ToString() + ") at: " +
|
|
fs.Position);
|
|
myStateFrameBlock.StatePointer[i].StateBlock.StateBlockHandlers[ii].CodeChunkPointer =
|
|
myStateFrameBlock.StatePointer[i].StateBlock.EndPos +
|
|
BitConverter.ToUInt32(br_read(4), 0);
|
|
myStateFrameBlock.StatePointer[i].StateBlock.StateBlockHandlers[ii].CallFrameSize =
|
|
BitConverter.ToUInt32(br_read(4), 0);
|
|
Common.SendToDebug("Reading STATE BLOCK " + (i + 1) + " HANDLER EVENT MASK " + ii + " (" +
|
|
((LSO_Enums.Event_Mask_Values) ii).ToString() + ") Code Chunk Pointer: " +
|
|
myStateFrameBlock.StatePointer[i].StateBlock.StateBlockHandlers[ii].
|
|
CodeChunkPointer);
|
|
Common.SendToDebug("Reading STATE BLOCK " + (i + 1) + " HANDLER EVENT MASK " + ii + " (" +
|
|
((LSO_Enums.Event_Mask_Values) ii).ToString() + ") Call Frame Size: " +
|
|
myStateFrameBlock.StatePointer[i].StateBlock.StateBlockHandlers[ii].
|
|
CallFrameSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//// READ FUNCTION CODE CHUNKS
|
|
//// Functions + Function start pos (GFR)
|
|
//// TODO: Somehow be able to identify and reference this
|
|
//LSO_Struct.CodeChunk[] myFunctionCodeChunk;
|
|
//if (myFunctionBlock.FunctionCount > 0)
|
|
//{
|
|
// myFunctionCodeChunk = new LSO_Struct.CodeChunk[myFunctionBlock.FunctionCount];
|
|
// for (int i = 0; i < myFunctionBlock.FunctionCount; i++)
|
|
// {
|
|
// Common.SendToDebug("Reading Function Code Chunk " + i);
|
|
// myFunctionCodeChunk[i] = GetCodeChunk((UInt32)myFunctionBlock.CodeChunkPointer[i]);
|
|
// }
|
|
|
|
//}
|
|
// READ EVENT CODE CHUNKS
|
|
LSO_Struct.CodeChunk[] myEventCodeChunk;
|
|
if (myStateFrameBlock.StateCount > 0)
|
|
{
|
|
myEventCodeChunk = new LSO_Struct.CodeChunk[myStateFrameBlock.StateCount];
|
|
for (int i = 0; i < myStateFrameBlock.StateCount; i++)
|
|
{
|
|
// TODO: Somehow organize events and functions so they can be found again,
|
|
// two level search ain't no good
|
|
for (int ii = 0; ii < myStateFrameBlock.StatePointer[i].EventMask.Count - 1; ii++)
|
|
{
|
|
if (myStateFrameBlock.StatePointer[i].StateBlock.StateBlockHandlers[ii].CodeChunkPointer > 0)
|
|
{
|
|
Common.SendToDebug("Reading Event Code Chunk state " + i + ", event " +
|
|
(LSO_Enums.Event_Mask_Values) ii);
|
|
|
|
|
|
// Override a Method / Function
|
|
string eventname = i + "_event_" + (LSO_Enums.Event_Mask_Values) ii;
|
|
Common.SendToDebug("Event Name: " + eventname);
|
|
if (Common.IL_ProcessCodeChunks)
|
|
{
|
|
EventList.Add(eventname);
|
|
|
|
// JUMP TO CODE PROCESSOR
|
|
ProcessCodeChunk(
|
|
myStateFrameBlock.StatePointer[i].StateBlock.StateBlockHandlers[ii].CodeChunkPointer,
|
|
typeBuilder, eventname);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (Common.IL_CreateFunctionList)
|
|
IL_INSERT_FUNCTIONLIST();
|
|
}
|
|
|
|
internal LSO_Struct.HeapBlock GetHeap(UInt32 pos)
|
|
{
|
|
// HEAP BLOCK
|
|
// TODO:? Special read for strings/keys (null terminated) and lists (pointers to other HEAP entries)
|
|
Common.SendToDebug("Reading HEAP BLOCK at: " + pos);
|
|
fs.Seek(pos, SeekOrigin.Begin);
|
|
|
|
LSO_Struct.HeapBlock myHeapBlock = new LSO_Struct.HeapBlock();
|
|
myHeapBlock.DataBlockSize = BitConverter.ToInt32(br_read(4), 0);
|
|
myHeapBlock.ObjectType = br_read(1)[0];
|
|
myHeapBlock.ReferenceCount = BitConverter.ToUInt16(br_read(2), 0);
|
|
//myHeapBlock.Data = br_read(getObjectSize(myHeapBlock.ObjectType));
|
|
// Don't read it reversed
|
|
myHeapBlock.Data = new byte[myHeapBlock.DataBlockSize - 1];
|
|
br.Read(myHeapBlock.Data, 0, myHeapBlock.DataBlockSize - 1);
|
|
|
|
|
|
Common.SendToDebug("Heap Block Data Block Size: " + myHeapBlock.DataBlockSize);
|
|
Common.SendToDebug("Heap Block ObjectType: " +
|
|
((LSO_Enums.Variable_Type_Codes) myHeapBlock.ObjectType).ToString());
|
|
Common.SendToDebug("Heap Block Reference Count: " + myHeapBlock.ReferenceCount);
|
|
|
|
return myHeapBlock;
|
|
}
|
|
|
|
private byte[] br_read(int len)
|
|
{
|
|
if (len <= 0)
|
|
return null;
|
|
|
|
try
|
|
{
|
|
byte[] bytes = new byte[len];
|
|
for (int i = len - 1; i > -1; i--)
|
|
bytes[i] = br.ReadByte();
|
|
return bytes;
|
|
}
|
|
catch (Exception e) // NOTLEGIT: No user related exceptions throwable here?
|
|
{
|
|
Common.SendToDebug("Exception: " + e.ToString());
|
|
throw (e);
|
|
}
|
|
}
|
|
|
|
//private byte[] br_read_smallendian(int len)
|
|
//{
|
|
// byte[] bytes = new byte[len];
|
|
// br.Read(bytes,0, len);
|
|
// return bytes;
|
|
//}
|
|
private Type getLLObjectType(byte objectCode)
|
|
{
|
|
switch ((LSO_Enums.Variable_Type_Codes) objectCode)
|
|
{
|
|
case LSO_Enums.Variable_Type_Codes.Void:
|
|
return typeof (void);
|
|
case LSO_Enums.Variable_Type_Codes.Integer:
|
|
return typeof (UInt32);
|
|
case LSO_Enums.Variable_Type_Codes.Float:
|
|
return typeof (float);
|
|
case LSO_Enums.Variable_Type_Codes.String:
|
|
return typeof (string);
|
|
case LSO_Enums.Variable_Type_Codes.Key:
|
|
return typeof (string);
|
|
case LSO_Enums.Variable_Type_Codes.Vector:
|
|
return typeof (LSO_Enums.Vector);
|
|
case LSO_Enums.Variable_Type_Codes.Rotation:
|
|
return typeof (LSO_Enums.Rotation);
|
|
case LSO_Enums.Variable_Type_Codes.List:
|
|
Common.SendToDebug("TODO: List datatype not implemented yet!");
|
|
return typeof (ArrayList);
|
|
case LSO_Enums.Variable_Type_Codes.Null:
|
|
Common.SendToDebug("TODO: Datatype null is not implemented, using string instead.!");
|
|
return typeof (string);
|
|
default:
|
|
Common.SendToDebug("Lookup of LSL datatype " + objectCode +
|
|
" to .Net datatype failed: Unknown LSL datatype. Defaulting to object.");
|
|
return typeof (object);
|
|
}
|
|
}
|
|
|
|
private int getObjectSize(byte ObjectType)
|
|
{
|
|
switch ((LSO_Enums.Variable_Type_Codes) ObjectType)
|
|
{
|
|
case LSO_Enums.Variable_Type_Codes.Integer:
|
|
case LSO_Enums.Variable_Type_Codes.Float:
|
|
case LSO_Enums.Variable_Type_Codes.String:
|
|
case LSO_Enums.Variable_Type_Codes.Key:
|
|
case LSO_Enums.Variable_Type_Codes.List:
|
|
return 4;
|
|
case LSO_Enums.Variable_Type_Codes.Vector:
|
|
return 12;
|
|
case LSO_Enums.Variable_Type_Codes.Rotation:
|
|
return 16;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private string Read_String()
|
|
{
|
|
string ret = String.Empty;
|
|
byte reader = br_read(1)[0];
|
|
while (reader != 0x000)
|
|
{
|
|
ret += (char) reader;
|
|
reader = br_read(1)[0];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a code chunk and creates IL
|
|
/// </summary>
|
|
/// <param name="pos">Absolute position in file. REMEMBER TO ADD myHeader.GFR!</param>
|
|
/// <param name="typeBuilder">TypeBuilder for assembly</param>
|
|
/// <param name="eventname">Name of event (function) to generate</param>
|
|
private void ProcessCodeChunk(UInt32 pos, TypeBuilder typeBuilder, string eventname)
|
|
{
|
|
LSO_Struct.CodeChunk myCodeChunk = new LSO_Struct.CodeChunk();
|
|
|
|
Common.SendToDebug("Reading Function Code Chunk at: " + pos);
|
|
fs.Seek(pos, SeekOrigin.Begin);
|
|
myCodeChunk.CodeChunkHeaderSize = BitConverter.ToUInt32(br_read(4), 0);
|
|
Common.SendToDebug("CodeChunk Header Size: " + myCodeChunk.CodeChunkHeaderSize);
|
|
// Read until null
|
|
myCodeChunk.Comment = Read_String();
|
|
Common.SendToDebug("Function comment: " + myCodeChunk.Comment);
|
|
myCodeChunk.ReturnTypePos = br_read(1)[0];
|
|
myCodeChunk.ReturnType = GetStaticBlock((long) myCodeChunk.ReturnTypePos + (long) myHeader.GVR);
|
|
Common.SendToDebug("Return type #" + myCodeChunk.ReturnType.ObjectType + ": " +
|
|
((LSO_Enums.Variable_Type_Codes) myCodeChunk.ReturnType.ObjectType).ToString());
|
|
|
|
|
|
// TODO: How to determine number of codechunks -- does this method work?
|
|
myCodeChunk.CodeChunkArguments = new List<LSO_Struct.CodeChunkArgument>();
|
|
byte reader = br_read(1)[0];
|
|
reader = br_read(1)[0];
|
|
|
|
// NOTE ON CODE CHUNK ARGUMENTS
|
|
// This determins type definition
|
|
int ccount = 0;
|
|
while (reader != 0x000)
|
|
{
|
|
ccount++;
|
|
Common.SendToDebug("Reading Code Chunk Argument " + ccount);
|
|
LSO_Struct.CodeChunkArgument CCA = new LSO_Struct.CodeChunkArgument();
|
|
CCA.FunctionReturnTypePos = reader;
|
|
reader = br_read(1)[0];
|
|
CCA.NullString = reader;
|
|
CCA.FunctionReturnType = GetStaticBlock(CCA.FunctionReturnTypePos + myHeader.GVR);
|
|
myCodeChunk.CodeChunkArguments.Add(CCA);
|
|
Common.SendToDebug("Code Chunk Argument " + ccount + " type #" + CCA.FunctionReturnType.ObjectType +
|
|
": " + (LSO_Enums.Variable_Type_Codes) CCA.FunctionReturnType.ObjectType);
|
|
}
|
|
// Create string array
|
|
Type[] MethodArgs = new Type[myCodeChunk.CodeChunkArguments.Count];
|
|
for (int _ic = 0; _ic < myCodeChunk.CodeChunkArguments.Count; _ic++)
|
|
{
|
|
MethodArgs[_ic] = getLLObjectType(myCodeChunk.CodeChunkArguments[_ic].FunctionReturnType.ObjectType);
|
|
Common.SendToDebug("Method argument " + _ic + ": " +
|
|
getLLObjectType(myCodeChunk.CodeChunkArguments[_ic].FunctionReturnType.ObjectType).
|
|
ToString());
|
|
}
|
|
// End marker is 0x000
|
|
myCodeChunk.EndMarker = reader;
|
|
|
|
|
|
//
|
|
// Emit: START OF METHOD (FUNCTION)
|
|
//
|
|
|
|
Common.SendToDebug("CLR:" + eventname + ":MethodBuilder methodBuilder = typeBuilder.DefineMethod...");
|
|
MethodBuilder methodBuilder = typeBuilder.DefineMethod(eventname,
|
|
MethodAttributes.Public,
|
|
typeof (void),
|
|
new Type[] {typeof (object)});
|
|
//MethodArgs);
|
|
//typeof(void), //getLLObjectType(myCodeChunk.ReturnType),
|
|
// new Type[] { typeof(object) }, //);
|
|
|
|
//Common.SendToDebug("CLR:" + eventname + ":typeBuilder.DefineMethodOverride(methodBuilder...");
|
|
//typeBuilder.DefineMethodOverride(methodBuilder,
|
|
// typeof(LSL_CLRInterface.LSLScript).GetMethod(eventname));
|
|
|
|
// Create the IL generator
|
|
|
|
Common.SendToDebug("CLR:" + eventname + ":ILGenerator il = methodBuilder.GetILGenerator();");
|
|
ILGenerator il = methodBuilder.GetILGenerator();
|
|
|
|
|
|
if (Common.IL_UseTryCatch)
|
|
IL_INSERT_TRY(il, eventname);
|
|
|
|
|
|
// Push Console.WriteLine command to stack ... Console.WriteLine("Hello World!");
|
|
//Common.SendToDebug("CLR:" + eventname + ":il.Emit(OpCodes.Call...");
|
|
//il.Emit(OpCodes.Call, typeof(Console).GetMethod
|
|
// ("WriteLine", new Type[] { typeof(string) }));
|
|
|
|
//Common.SendToDebug("STARTUP: il.Emit(OpCodes.Ldc_I4_S, 0);");
|
|
|
|
//il.Emit(OpCodes.Ldc_I4_S, 0);
|
|
for (int _ic = 0; _ic < myCodeChunk.CodeChunkArguments.Count; _ic++)
|
|
{
|
|
Common.SendToDebug("PARAMS: il.Emit(OpCodes.Ldarg, " + _ic + ");");
|
|
il.Emit(OpCodes.Ldarg, _ic);
|
|
}
|
|
|
|
|
|
//
|
|
// CALLING OPCODE PROCESSOR, one command at the time TO GENERATE IL
|
|
//
|
|
bool FoundRet = false;
|
|
while (FoundRet == false)
|
|
{
|
|
FoundRet = LSL_PROCESS_OPCODE(il);
|
|
}
|
|
|
|
|
|
if (Common.IL_UseTryCatch)
|
|
IL_INSERT_END_TRY(il, eventname);
|
|
|
|
// Emit: RETURN FROM METHOD
|
|
il.Emit(OpCodes.Ret);
|
|
|
|
return;
|
|
}
|
|
|
|
private void IL_INSERT_FUNCTIONLIST()
|
|
{
|
|
Common.SendToDebug("Creating function list");
|
|
|
|
|
|
string eventname = "GetFunctions";
|
|
|
|
Common.SendToDebug("Creating IL " + eventname);
|
|
// Define a private String field.
|
|
//FieldBuilder myField = myTypeBuilder.DefineField("EventList", typeof(String[]), FieldAttributes.Public);
|
|
|
|
|
|
//FieldBuilder mem = typeBuilder.DefineField("mem", typeof(Array), FieldAttributes.Private);
|
|
|
|
|
|
MethodBuilder methodBuilder = typeBuilder.DefineMethod(eventname,
|
|
MethodAttributes.Public,
|
|
typeof (string[]),
|
|
null);
|
|
|
|
//typeBuilder.DefineMethodOverride(methodBuilder,
|
|
// typeof(LSL_CLRInterface.LSLScript).GetMethod(eventname));
|
|
|
|
ILGenerator il = methodBuilder.GetILGenerator();
|
|
|
|
|
|
// IL_INSERT_TRY(il, eventname);
|
|
|
|
// // Push string to stack
|
|
// il.Emit(OpCodes.Ldstr, "Inside " + eventname);
|
|
|
|
//// Push Console.WriteLine command to stack ... Console.WriteLine("Hello World!");
|
|
//il.Emit(OpCodes.Call, typeof(Console).GetMethod
|
|
// ("WriteLine", new Type[] { typeof(string) }));
|
|
|
|
//initIL.Emit(OpCodes.Newobj, typeof(string[]));
|
|
|
|
//string[] MyArray = new string[2] { "TestItem1" , "TestItem2" };
|
|
|
|
////il.Emit(OpCodes.Ldarg_0);
|
|
|
|
il.DeclareLocal(typeof (string[]));
|
|
|
|
////il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Ldc_I4, EventList.Count); // Specify array length
|
|
il.Emit(OpCodes.Newarr, typeof (String)); // create new string array
|
|
il.Emit(OpCodes.Stloc_0); // Store array as local variable 0 in stack
|
|
////SetFunctionList
|
|
|
|
for (int lv = 0; lv < EventList.Count; lv++)
|
|
{
|
|
il.Emit(OpCodes.Ldloc_0); // Load local variable 0 onto stack
|
|
il.Emit(OpCodes.Ldc_I4, lv); // Push index position
|
|
il.Emit(OpCodes.Ldstr, EventList[lv]); // Push value
|
|
il.Emit(OpCodes.Stelem_Ref); // Perform array[index] = value
|
|
|
|
//il.Emit(OpCodes.Ldarg_0);
|
|
//il.Emit(OpCodes.Ldstr, EventList[lv]); // Push value
|
|
//il.Emit(OpCodes.Call, typeof(LSL_BaseClass).GetMethod("AddFunction", new Type[] { typeof(string) }));
|
|
}
|
|
|
|
|
|
// IL_INSERT_END_TRY(il, eventname);
|
|
|
|
|
|
il.Emit(OpCodes.Ldloc_0); // Load local variable 0 onto stack
|
|
// il.Emit(OpCodes.Call, typeof(LSL_BaseClass).GetMethod("SetFunctionList", new Type[] { typeof(Array) }));
|
|
|
|
il.Emit(OpCodes.Ret); // Return
|
|
}
|
|
|
|
|
|
private void IL_INSERT_TRY(ILGenerator il, string eventname)
|
|
{
|
|
/*
|
|
* CLR TRY
|
|
*/
|
|
//Common.SendToDebug("CLR:" + eventname + ":il.BeginExceptionBlock()");
|
|
il.BeginExceptionBlock();
|
|
|
|
// Push "Hello World!" string to stack
|
|
//Common.SendToDebug("CLR:" + eventname + ":il.Emit(OpCodes.Ldstr...");
|
|
//il.Emit(OpCodes.Ldstr, "Starting CLR dynamic execution of: " + eventname);
|
|
}
|
|
|
|
private void IL_INSERT_END_TRY(ILGenerator il, string eventname)
|
|
{
|
|
/*
|
|
* CATCH
|
|
*/
|
|
Common.SendToDebug("CLR:" + eventname + ":il.BeginCatchBlock(typeof(Exception));");
|
|
il.BeginCatchBlock(typeof (Exception));
|
|
|
|
// Push "Hello World!" string to stack
|
|
Common.SendToDebug("CLR:" + eventname + ":il.Emit(OpCodes.Ldstr...");
|
|
il.Emit(OpCodes.Ldstr, "Execption executing dynamic CLR function " + eventname + ": ");
|
|
|
|
//call void [mscorlib]System.Console::WriteLine(string)
|
|
Common.SendToDebug("CLR:" + eventname + ":il.Emit(OpCodes.Call...");
|
|
il.Emit(OpCodes.Call, typeof (Console).GetMethod
|
|
("Write", new Type[] {typeof (string)}));
|
|
|
|
//callvirt instance string [mscorlib]System.Exception::get_Message()
|
|
Common.SendToDebug("CLR:" + eventname + ":il.Emit(OpCodes.Callvirt...");
|
|
il.Emit(OpCodes.Callvirt, typeof (Exception).GetMethod
|
|
("get_Message"));
|
|
|
|
//call void [mscorlib]System.Console::WriteLine(string)
|
|
Common.SendToDebug("CLR:" + eventname + ":il.Emit(OpCodes.Call...");
|
|
il.Emit(OpCodes.Call, typeof (Console).GetMethod
|
|
("WriteLine", new Type[] {typeof (string)}));
|
|
|
|
/*
|
|
* CLR END TRY
|
|
*/
|
|
//Common.SendToDebug("CLR:" + eventname + ":il.EndExceptionBlock();");
|
|
il.EndExceptionBlock();
|
|
}
|
|
|
|
private LSO_Struct.StaticBlock GetStaticBlock(long pos)
|
|
{
|
|
long FirstPos = fs.Position;
|
|
try
|
|
{
|
|
UInt32 position = (UInt32) pos;
|
|
// STATIC BLOCK
|
|
Common.SendToDebug("Reading STATIC BLOCK at: " + position);
|
|
fs.Seek(position, SeekOrigin.Begin);
|
|
|
|
if (StaticBlocks.ContainsKey(position) == true)
|
|
{
|
|
Common.SendToDebug("Found cached STATIC BLOCK");
|
|
|
|
|
|
return StaticBlocks[pos];
|
|
}
|
|
|
|
//int StaticBlockCount = 0;
|
|
// Read function blocks until we hit GFR
|
|
//while (fs.Position < myHeader.GFR)
|
|
//{
|
|
//StaticBlockCount++;
|
|
|
|
//Common.SendToDebug("Reading Static Block at: " + position);
|
|
|
|
//fs.Seek(myHeader.GVR, SeekOrigin.Begin);
|
|
LSO_Struct.StaticBlock myStaticBlock = new LSO_Struct.StaticBlock();
|
|
myStaticBlock.Static_Chunk_Header_Size = BitConverter.ToUInt32(br_read(4), 0);
|
|
myStaticBlock.ObjectType = br_read(1)[0];
|
|
Common.SendToDebug("Static Block ObjectType: " +
|
|
((LSO_Enums.Variable_Type_Codes) myStaticBlock.ObjectType).ToString());
|
|
myStaticBlock.Unknown = br_read(1)[0];
|
|
// Size of datatype varies
|
|
if (myStaticBlock.ObjectType != 0)
|
|
myStaticBlock.BlockVariable = br_read(getObjectSize(myStaticBlock.ObjectType));
|
|
|
|
StaticBlocks.Add(position, myStaticBlock);
|
|
//}
|
|
Common.SendToDebug("Done reading Static Block.");
|
|
return myStaticBlock;
|
|
}
|
|
finally
|
|
{
|
|
// Go back to original read pos
|
|
fs.Seek(FirstPos, SeekOrigin.Begin);
|
|
}
|
|
}
|
|
}
|
|
} |