Editor/Inference/LiteModel.cs

A small TFLite flatbuffer reader used in the Editor. It parses a TFLite model byte array, extracts tensors and operators into managed records, reads shapes, types and constant values (supports float32, float16, and int32), and exposes graph inputs and outputs. It does not invoke native runtimes and enforces simple size checks.

File AccessObfuscated Code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace HumanoidMocap.EditorTools.Inference;

/// <summary>Read-only subset of the documented TFLite flatbuffer format. No native runtime.</summary>
public sealed class LiteModel
{
    public sealed record Tensor(string Name,int[] Shape,int Type,float[] Values,bool Constant);
    public sealed record Operator(int Code,int[] Inputs,int[] Outputs,int Options);
    public List<Tensor> Tensors { get; } = new();
    public List<Operator> Operators { get; } = new();
    public int[] Inputs { get; }
    public int[] Outputs { get; }
    readonly byte[] data;
    int I(int p)=>BitConverter.ToInt32(data,p);
    ushort U(int p)=>BitConverter.ToUInt16(data,p);
    public int Field(int table,int field)
    {
        if(table==0)return 0;var vt=table-I(table);var index=4+field*2;
        return index<U(vt) && U(vt+index)!=0?table+U(vt+index):0;
    }
    int Ref(int at)=>at==0?0:at+I(at);
    public int Int(int table,int field,int fallback=0){var p=Field(table,field);return p==0?fallback:I(p);}
    public int Byte(int table,int field,int fallback=0){var p=Field(table,field);return p==0?fallback:data[p];}
    int[] Array(int table,int field,bool refs=false)
    {
        var p=Ref(Field(table,field));if(p==0)return System.Array.Empty<int>();
        var n=I(p);if(n<0||n>1000000)throw new FormatException("Invalid model vector size.");
        return Enumerable.Range(0,n).Select(i=>refs?Ref(p+4+i*4):I(p+4+i*4)).ToArray();
    }
    string String(int table,int field)
    {
        var p=Ref(Field(table,field));return p==0?"":Encoding.UTF8.GetString(data,p+4,I(p));
    }
    public LiteModel(byte[] bytes)
    {
        data=bytes;
        if(bytes.Length<8||Encoding.ASCII.GetString(bytes,4,4)!="TFL3")throw new FormatException("Not a TFLite model.");
        var root=I(0);var codes=Array(root,1,true);var subgraphs=Array(root,2,true);var buffers=Array(root,4,true);
        if(subgraphs.Length!=1)throw new NotSupportedException("Only single-graph inference is supported.");
        var graph=subgraphs[0];Inputs=Array(graph,1);Outputs=Array(graph,2);
        long total=0;
        foreach(var t in Array(graph,0,true))
        {
            var shape=Array(t,0);var count=shape.Aggregate(1,(a,b)=>checked(a*b));total+=count;
            if(count<0||total>200000000)throw new FormatException("Model exceeds managed inference budget.");
            var type=Byte(t,1);var buffer=Int(t,2);var offset=Ref(Field(buffers[buffer],0));var length=offset==0?0:I(offset);
            var values=new float[count];
            if(length>0)
            {
                var stride=type switch{0 or 2=>4,1=>2,_=>throw new NotSupportedException($"Tensor type {type} is not supported.")};
                if(length!=count*stride)throw new FormatException("Tensor size mismatch.");
                for(var i=0;i<count;i++)values[i]=type switch
                {0=>BitConverter.ToSingle(data,offset+4+i*4),1=>HalfToFloat(U(offset+4+i*2)),2=>I(offset+4+i*4),_=>0};
            }
            Tensors.Add(new(String(t,3),shape,type,values,length>0));
        }
        foreach(var op in Array(graph,3,true))
        {
            var code=codes[Int(op,0)];var builtin=Int(code,3,Byte(code,0));
            Operators.Add(new(builtin,Array(op,1),Array(op,2),Ref(Field(op,4))));
        }
    }
    static float HalfToFloat(ushort bits)
    {
        var sign=(bits&0x8000)==0?1f:-1f;var exponent=(bits>>10)&31;var mantissa=bits&1023;
        if(exponent==0)return sign*MathF.Pow(2,-14)*(mantissa/1024f);
        if(exponent==31)return mantissa==0?sign*float.PositiveInfinity:float.NaN;
        return sign*MathF.Pow(2,exponent-15)*(1+mantissa/1024f);
    }
}