158 lines
6.2 KiB
C#
158 lines
6.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using TLang.Common;
|
|
|
|
namespace TLang.VM
|
|
{
|
|
public class TVMFile
|
|
{
|
|
public List<Class> Classes {get;set;}=new List<Class>();
|
|
public List<Function> Functions {get;set;}=new List<Function>();
|
|
public List<TLangDependency> Dependencies {get;set;}=new List<TLangDependency>();
|
|
|
|
public List<Chunk> Chunks {get;set;}=new List<Chunk>();
|
|
public TLangVersion Version {get;set;}
|
|
public RootEnvironment Environment {get;private set;}
|
|
|
|
public ChunkExecuter DefaultChunkExecuter => new ChunkExecuter(this,Chunks[0],Environment);
|
|
public TVMFile(Stream file,RootEnvironment env)
|
|
{
|
|
Environment = env;
|
|
byte[] data=new byte[11];
|
|
int read=file.Read(data,0,data.Length);
|
|
CheckData(data,read);
|
|
int deps=ReadBigEndianIntenger(file);
|
|
for(int i = 0;i<deps;i++)
|
|
{
|
|
int nameLen = ReadBigEndianIntenger(file);
|
|
data = new byte[nameLen];
|
|
EnsureRead(file,data);
|
|
string name = System.Text.Encoding.UTF8.GetString(data);
|
|
data = new byte[4];
|
|
EnsureRead(file,data);
|
|
var version = TLangVersion.FromBytes(data,0);
|
|
Dependencies.Add(new TLangDependency(name,version));
|
|
}
|
|
int funcsLen = ReadBigEndianIntenger(file);
|
|
for(int i = 0;i<funcsLen;i++)
|
|
{
|
|
int nameLen = ReadBigEndianIntenger(file);
|
|
data = new byte[nameLen];
|
|
EnsureRead(file,data);
|
|
string name = System.Text.Encoding.UTF8.GetString(data);
|
|
int chunkId = ReadBigEndianIntenger(file);
|
|
Functions.Add(new Function(){Name = name,ChunkId = chunkId});
|
|
}
|
|
int classLen = ReadBigEndianIntenger(file);
|
|
for(int i = 0;i<classLen;i++)
|
|
{
|
|
int nameLen = ReadBigEndianIntenger(file);
|
|
data = new byte[nameLen];
|
|
EnsureRead(file,data);
|
|
string name = System.Text.Encoding.UTF8.GetString(data);
|
|
nameLen = ReadBigEndianIntenger(file);
|
|
data = new byte[nameLen];
|
|
EnsureRead(file,data);
|
|
string inheritsFrom = System.Text.Encoding.UTF8.GetString(data);
|
|
Class classes = new Class();
|
|
classes.Name = name;
|
|
classes.InheritsFrom = inheritsFrom;
|
|
|
|
int classEntryCount = ReadBigEndianIntenger(file);
|
|
for(int j = 0;j<classEntryCount;j++)
|
|
{
|
|
int modifier = file.ReadByte();
|
|
if(modifier == -1) throw new IOException("End of file");
|
|
nameLen = ReadBigEndianIntenger(file);
|
|
data = new byte[nameLen];
|
|
EnsureRead(file,data);
|
|
string name2 = System.Text.Encoding.UTF8.GetString(data);
|
|
int chunkId = ReadBigEndianIntenger(file);
|
|
classes.ClassEntries.Add(new ClassEntry(){Modifier = (byte)modifier, Name = name2, ChunkId = chunkId});
|
|
}
|
|
Classes.Add(classes);
|
|
}
|
|
int chunks = ReadBigEndianIntenger(file);
|
|
for(int i = 0;i<chunks;i++)
|
|
{
|
|
Chunk chunk = new Chunk();
|
|
|
|
int argCount = ReadBigEndianIntenger(file);
|
|
for(int j = 0;j<argCount;j++)
|
|
{
|
|
int nameLen = ReadBigEndianIntenger(file);
|
|
data = new byte[nameLen];
|
|
EnsureRead(file,data);
|
|
string name2 = System.Text.Encoding.UTF8.GetString(data);
|
|
chunk.Arguments.Add(name2);
|
|
}
|
|
|
|
int length = ReadBigEndianIntenger(file);
|
|
var code = new byte[length];
|
|
int offset = 0;
|
|
int read0 = 0;
|
|
do{
|
|
read0 = Math.Min(length-offset,1024);
|
|
if(read0 > 0)
|
|
read0=file.Read(code,offset,read0);
|
|
|
|
offset+=read0;
|
|
} while(read0 > 0);
|
|
chunk.Code = code;
|
|
Chunks.Add(chunk);
|
|
}
|
|
}
|
|
private void EnsureRead(Stream file,byte[] data)
|
|
{
|
|
int i = file.Read(data,0,data.Length);
|
|
if(i != data.Length) throw new IndexOutOfRangeException("Array must be filled");
|
|
|
|
}
|
|
private int ReadBigEndianIntenger(Stream file)
|
|
{
|
|
byte[] bytes=new byte[4];
|
|
EnsureRead(file,bytes);
|
|
if(BitConverter.IsLittleEndian) Array.Reverse(bytes);
|
|
return BitConverter.ToInt32(bytes,0);
|
|
}
|
|
|
|
private void CheckData(byte[] data, int read)
|
|
{
|
|
if(read < 11 || data[0] != 'T' || data[1] != 'V' || data[2] != 'M') throw new BadImageFormatException("TVM file invalid");
|
|
|
|
if(TLangVersion.FromBytes(data,3).IntegerVersion > TLangVersion.Version.IntegerVersion) throw new BadImageFormatException("TVM Version is too old");
|
|
|
|
Version = TLangVersion.FromBytes(data,7);
|
|
|
|
}
|
|
|
|
public bool LoadDependencies(IDependencyPool dependencyPool)
|
|
{
|
|
foreach(var dep in Dependencies)
|
|
{
|
|
if(!dependencyPool.DependencyExists(dep))
|
|
{
|
|
if(!dependencyPool.AddDependency(dep,Environment)) return false;
|
|
}
|
|
}
|
|
foreach(var func in Functions)
|
|
{
|
|
Environment.SetObject(func.Name,new TClosure(this,Chunks[func.ChunkId],Environment));
|
|
}
|
|
foreach(var class0 in Classes)
|
|
{
|
|
Environment.AvailableClasses.Add(class0.Name,new LoadedClassData(class0.InheritsFrom,this,class0.ClassEntries));
|
|
Environment.SetObject(class0.Name,new TExternalMethod(args=>{
|
|
TClassInstance instance = new TClassInstance(this,class0,Environment);
|
|
instance.Init(args);
|
|
return instance;
|
|
}));
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
} |