/* * Copyright (c) Contributors, http://www.openmetaverse.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. * */ using System; using System.IO; using System.Collections.Generic; using System.Text; using OpenSim.Scripting.EmbeddedJVM.Types; namespace OpenSim.Scripting.EmbeddedJVM { public class ClassRecord { private ushort _majorVersion; private ushort _minorVersion; private ushort _constantPoolCount; private ushort _accessFlags; private ushort _thisClass; private ushort _supperClass; private ushort _interfaceCount; private ushort _fieldCount; private ushort _methodCount; //private ushort _attributeCount; //private string _name; public Dictionary StaticFields = new Dictionary(); public PoolClass mClass; public List _constantsPool = new List(); private List _methodsList = new List(); private List _fieldList = new List(); public ClassRecord() { } public ClassInstance CreateNewInstance() { return new ClassInstance(); } public void LoadClassFromFile(string fileName) { Console.WriteLine("loading script " + fileName); FileStream fs = File.OpenRead(fileName); this.LoadClassFromBytes(ReadFully(fs)); fs.Close(); } public void LoadClassFromBytes(byte[] data) { int i = 0; i += 4; _minorVersion = (ushort)((data[i++] << 8) + data[i++] ); _majorVersion = (ushort)((data[i++] << 8) + data[i++] ); _constantPoolCount = (ushort)((data[i++] << 8) + data[i++] ); // Console.WriteLine("there should be " + _constantPoolCount + " items in the pool"); for (int count = 0; count < _constantPoolCount -1 ; count++) { //read in the constant pool byte pooltype = data[i++]; //Console.WriteLine("#" +count +": new constant type = " +pooltype); //Console.WriteLine("start position is: " + i); switch (pooltype) { case 1: //Utf8 ushort uLength = (ushort)((data[i++] << 8) + data[i++] ); // Console.WriteLine("new utf8 type, length is " + uLength); PoolUtf8 utf8 = new PoolUtf8(); utf8.readValue(data, ref i, uLength); this._constantsPool.Add(utf8); break; case 3: //Int break; case 7: //Class PoolClass pClass = new PoolClass(this); pClass.readValue(data, ref i); this._constantsPool.Add(pClass); break; case 10: //Method PoolMethodRef pMeth = new PoolMethodRef(this); pMeth.readValue(data, ref i); this._constantsPool.Add(pMeth); break; case 12: //NamedType PoolNamedType pNamed = new PoolNamedType(this); pNamed.readValue(data, ref i); this._constantsPool.Add(pNamed); break; } } _accessFlags = (ushort)((data[i++] << 8) + data[i++] ); _thisClass = (ushort)((data[i++] << 8) + data[i++] ); _supperClass = (ushort)((data[i++] << 8) + data[i++] ); if (this._constantsPool[this._thisClass - 1] is PoolClass) { this.mClass = ((PoolClass)this._constantsPool[this._thisClass - 1]); } _interfaceCount = (ushort)((data[i++] << 8) + data[i++]); //should now read in the info for each interface _fieldCount = (ushort)((data[i++] << 8) + data[i++]); //should now read in the info for each field _methodCount = (ushort)((data[i++] << 8) + data[i++]); for (int count = 0; count < _methodCount; count++) { MethodInfo methInf = new MethodInfo(this); methInf.ReadData(data, ref i); this._methodsList.Add(methInf); } } public void AddMethodsToMemory(MethodMemory memory) { for (int count = 0; count < _methodCount; count++) { this._methodsList[count].AddMethodCode(memory); } } public bool StartMethod(Thread thread, string methodName) { for (int count = 0; count < _methodCount; count++) { if (this._constantsPool[this._methodsList[count].NameIndex-1] is PoolUtf8) { if (((PoolUtf8)this._constantsPool[this._methodsList[count].NameIndex-1]).Value == methodName) { //Console.WriteLine("found method: " + ((PoolUtf8)this._constantsPool[this._methodsList[count].NameIndex - 1]).Value); thread.SetPC(this._methodsList[count].CodePointer); return true; } } } return false; } public void PrintToConsole() { Console.WriteLine("Class File:"); Console.WriteLine("Major version: " + _majorVersion); Console.WriteLine("Minor version: " + _minorVersion); Console.WriteLine("Pool size: " + _constantPoolCount); for (int i = 0; i < _constantsPool.Count; i++) { this._constantsPool[i].Print(); } Console.WriteLine("Access flags: " + _accessFlags); Console.WriteLine("This class: " + _thisClass ); Console.WriteLine("Super class: " + _supperClass); for (int count = 0; count < _methodCount; count++) { Console.WriteLine(); this._methodsList[count].Print(); } Console.WriteLine("class name is " + this.mClass.Name.Value); } public static byte[] ReadFully(Stream stream) { byte[] buffer = new byte[1024]; using (MemoryStream ms = new MemoryStream()) { while (true) { int read = stream.Read(buffer, 0, buffer.Length); if (read <= 0) return ms.ToArray(); ms.Write(buffer, 0, read); } } } #region nested classes public class PoolItem { public virtual void Print() { } } public class PoolUtf8 : PoolItem { public string Value = ""; public void readValue(byte[] data,ref int pointer , int length) { for (int i = 0; i < length; i++) { int a =(int) data[pointer++]; if ((a & 0x80) == 0) { Value = Value + (char)a; } else if ((a & 0x20) == 0) { int b = (int) data[pointer++]; Value = Value + (char)(((a & 0x1f) << 6) + (b & 0x3f)); } else { int b = (int)data[pointer++]; int c = (int)data[pointer++]; Value = Value + (char)(((a & 0xf) << 12) + ((b & 0x3f) << 6) + (c & 0x3f)); } } } public override void Print() { Console.WriteLine("Utf8 type: " + Value); } } private class PoolInt : PoolItem { } public class PoolClass : PoolItem { //public string name = ""; public ushort namePointer = 0; private ClassRecord parent; public PoolUtf8 Name; public PoolClass(ClassRecord paren) { parent = paren; } public void readValue(byte[] data, ref int pointer) { namePointer = (ushort)((data[pointer++] << 8) + data[pointer++] ); } public override void Print() { this.Name = ((PoolUtf8)this.parent._constantsPool[namePointer - 1]); Console.Write("Class type: " + namePointer); Console.WriteLine(" // " + ((PoolUtf8)this.parent._constantsPool[namePointer - 1]).Value); } } public class PoolMethodRef : PoolItem { public ushort classPointer = 0; public ushort nameTypePointer = 0; public PoolNamedType mNameType; public PoolClass mClass; private ClassRecord parent; public PoolMethodRef(ClassRecord paren) { parent = paren; } public void readValue(byte[] data, ref int pointer) { classPointer = (ushort)((data[pointer++] << 8) + data[pointer++]); nameTypePointer = (ushort)((data[pointer++] << 8) + data[pointer++]); } public override void Print() { this.mNameType = ((PoolNamedType)this.parent._constantsPool[nameTypePointer - 1]); this.mClass = ((PoolClass)this.parent._constantsPool[classPointer - 1]); Console.WriteLine("MethodRef type: " + classPointer + " , " + nameTypePointer); } } public class PoolNamedType : PoolItem { public ushort namePointer = 0; public ushort typePointer = 0; private ClassRecord parent; public PoolUtf8 Name; public PoolUtf8 Type; public PoolNamedType(ClassRecord paren) { parent = paren; } public void readValue(byte[] data, ref int pointer) { namePointer = (ushort)((data[pointer++] << 8) + data[pointer++] ); typePointer = (ushort)((data[pointer++] << 8) + data[pointer++] ); } public override void Print() { Name = ((PoolUtf8)this.parent._constantsPool[namePointer-1]); Type = ((PoolUtf8)this.parent._constantsPool[typePointer-1]); Console.Write("Named type: " + namePointer + " , " + typePointer ); Console.WriteLine(" // "+ ((PoolUtf8)this.parent._constantsPool[namePointer-1]).Value); } } //*********************** public class MethodInfo { public ushort AccessFlags = 0; public ushort NameIndex = 0; public string Name = ""; public ushort DescriptorIndex = 0; public ushort AttributeCount = 0; public List Attributes = new List(); private ClassRecord parent; public int CodePointer = 0; public MethodInfo(ClassRecord paren) { parent = paren; } public void AddMethodCode(MethodMemory memory) { Array.Copy(this.Attributes[0].Code, 0, memory.MethodBuffer, memory.NextMethodPC, this.Attributes[0].Code.Length); memory.Methodcount++; this.CodePointer = memory.NextMethodPC; memory.NextMethodPC += this.Attributes[0].Code.Length; } public void ReadData(byte[] data, ref int pointer) { AccessFlags = (ushort)((data[pointer++] << 8) + data[pointer++]); NameIndex = (ushort)((data[pointer++] << 8) + data[pointer++]); DescriptorIndex = (ushort)((data[pointer++] << 8) + data[pointer++]); AttributeCount = (ushort)((data[pointer++] << 8) + data[pointer++]); for(int i =0; i< AttributeCount; i++) { MethodAttribute attri = new MethodAttribute(this.parent); attri.ReadData(data, ref pointer); this.Attributes.Add(attri); } } public void Print() { Console.WriteLine("Method Info Struct: "); Console.WriteLine("AccessFlags: " + AccessFlags); Console.WriteLine("NameIndex: " + NameIndex +" // "+ ((PoolUtf8)this.parent._constantsPool[NameIndex-1]).Value); Console.WriteLine("DescriptorIndex: " + DescriptorIndex + " // "+ ((PoolUtf8)this.parent._constantsPool[DescriptorIndex-1]).Value); Console.WriteLine("Attribute Count:" + AttributeCount); for (int i = 0; i < AttributeCount; i++) { this.Attributes[i].Print(); } } public class MethodAttribute { public ushort NameIndex = 0; public string Name = ""; public Int32 Length = 0; //for now only support code attribute public ushort MaxStack = 0; public ushort MaxLocals = 0; public Int32 CodeLength = 0; public byte[] Code; public ushort ExceptionTableLength = 0; public ushort SubAttributeCount = 0; public List SubAttributes = new List(); private ClassRecord parent; public MethodAttribute(ClassRecord paren) { parent = paren; } public void ReadData(byte[] data, ref int pointer) { NameIndex = (ushort)((data[pointer++] << 8) + data[pointer++]); Length = (Int32)((data[pointer++] << 24) + (data[pointer++] << 16) + (data[pointer++] << 8) + data[pointer++]); MaxStack = (ushort)((data[pointer++] << 8) + data[pointer++]); MaxLocals = (ushort)((data[pointer++] << 8) + data[pointer++]); CodeLength = (Int32)((data[pointer++] << 24) + (data[pointer++] << 16) + (data[pointer++] << 8) + data[pointer++]); Code = new byte[CodeLength]; for (int i = 0; i < CodeLength; i++) { Code[i] = data[pointer++]; } ExceptionTableLength = (ushort)((data[pointer++] << 8) + data[pointer++]); SubAttributeCount = (ushort)((data[pointer++] << 8) + data[pointer++]); for (int i = 0; i < SubAttributeCount; i++) { SubAttribute subAttri = new SubAttribute(this.parent); subAttri.ReadData(data, ref pointer); this.SubAttributes.Add(subAttri); } } public void Print() { Console.WriteLine("Method Attribute: "); Console.WriteLine("Name Index: " + NameIndex + " // "+ ((PoolUtf8)this.parent._constantsPool[NameIndex-1]).Value); Console.WriteLine("Length: " + Length); Console.WriteLine("MaxStack: " + MaxStack); Console.WriteLine("MaxLocals: " + MaxLocals); Console.WriteLine("CodeLength: " + CodeLength); for (int i = 0; i < Code.Length; i++) { Console.WriteLine("OpCode #" + i + " is: " + Code[i]); } Console.WriteLine("SubAttributes: " + SubAttributeCount); for (int i = 0; i < SubAttributeCount; i++) { this.SubAttributes[i].Print(); } } public class SubAttribute { public ushort NameIndex = 0; public string Name = ""; public Int32 Length = 0; public byte[] Data; private ClassRecord parent; public SubAttribute(ClassRecord paren) { parent = paren; } public void ReadData(byte[] data, ref int pointer) { NameIndex = (ushort)((data[pointer++] << 8) + data[pointer++]); Length = (Int32)((data[pointer++] << 24) + (data[pointer++] << 16) + (data[pointer++] << 8) + data[pointer++]); Data = new byte[Length]; for (int i = 0; i < Length; i++) { Data[i] = data[pointer++]; } } public void Print() { Console.WriteLine("SubAttribute: NameIndex: " + NameIndex + " // " + ((PoolUtf8)this.parent._constantsPool[NameIndex - 1]).Value); } } } } private class InterfaceInfo { public void ReadData(byte[] data, ref int i) { } } private class FieldInfo { public void ReadData(byte[] data, ref int i) { } } private class AttributeInfo { public void ReadData(byte[] data, ref int i) { } } #endregion } }