// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS)
// Copyright (C) 2025-present LeonOS 2 Developer Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
// #define DEBUG_BINARY_READER
// #define DEBUG_UNDUMP
using System;
using ULDebug = UniLua.Tools.ULDebug;
namespace UniLua
{
public class BinaryBytesReader
{
private ILoadInfo LoadInfo;
public int SizeOfSizeT;
public BinaryBytesReader( ILoadInfo loadinfo )
{
LoadInfo = loadinfo;
SizeOfSizeT = 0;
}
public byte[] ReadBytes( int count )
{
byte[] ret = new byte[count];
for( int i=0; i Int32.MaxValue )
throw new NotImplementedException();
return (int)ret;
}
public double ReadDouble()
{
var bytes = ReadBytes( 8 );
double ret = BitConverter.ToDouble( bytes, 0 );
#if DEBUG_BINARY_READER
Console.WriteLine( "ReadDouble: " + ret );
#endif
return ret;
}
public byte ReadByte()
{
var c = LoadInfo.ReadByte();
if( c == -1 )
throw new UndumpException("truncated");
#if DEBUG_BINARY_READER
Console.WriteLine( "ReadBytes: " + c );
#endif
return (byte)c;
}
public string ReadString()
{
var n = ReadSizeT();
if( n == 0 )
return null;
var bytes = ReadBytes( n );
// n=1: removing trailing '\0'
string ret = System.Text.Encoding.ASCII.GetString( bytes, 0, n-1 );
#if DEBUG_BINARY_READER
Console.WriteLine( "ReadString n:" + n + " ret:" + ret );
#endif
return ret;
}
}
class UndumpException : Exception
{
public string Why;
public UndumpException( string why )
{
Why = why;
}
}
public class Undump
{
private BinaryBytesReader Reader;
public static LuaProto LoadBinary( ILuaState lua,
ILoadInfo loadinfo, string name )
{
try
{
var reader = new BinaryBytesReader( loadinfo );
var undump = new Undump( reader );
undump.LoadHeader();
return undump.LoadFunction();
}
catch( UndumpException e )
{
var Lua = (LuaState)lua;
Lua.O_PushString( string.Format(
"{0}: {1} precompiled chunk", name, e.Why ) );
Lua.D_Throw( ThreadStatus.LUA_ERRSYNTAX );
return null;
}
}
private Undump( BinaryBytesReader reader )
{
Reader = reader;
}
private int LoadInt()
{
return Reader.ReadInt();
}
private byte LoadByte()
{
return Reader.ReadByte();
}
private byte[] LoadBytes( int count )
{
return Reader.ReadBytes( count );
}
private string LoadString()
{
return Reader.ReadString();
}
private bool LoadBoolean()
{
return LoadByte() != 0;
}
private double LoadNumber()
{
return Reader.ReadDouble();
}
private void LoadHeader()
{
byte[] header = LoadBytes( 4 // Signature
+ 8 // version, format version, size of int ... etc
+ 6 // Tail
);
byte v = header[ 4 /* skip signature */
+ 4 /* offset of sizeof(size_t) */
];
#if DEBUG_UNDUMP
Console.WriteLine(string.Format("sizeof(size_t): {0}", v));
#endif
Reader.SizeOfSizeT = v ;
}
private Instruction LoadInstruction()
{
return (Instruction)Reader.ReadUInt();
}
private LuaProto LoadFunction()
{
#if DEBUG_UNDUMP
Console.WriteLine( "LoadFunction enter" );
#endif
LuaProto proto = new LuaProto();
proto.LineDefined = LoadInt();
proto.LastLineDefined = LoadInt();
proto.NumParams = LoadByte();
proto.IsVarArg = LoadBoolean();
proto.MaxStackSize = LoadByte();
LoadCode(proto);
LoadConstants(proto);
LoadUpvalues(proto);
LoadDebug(proto);
return proto;
}
private void LoadCode( LuaProto proto )
{
var n = LoadInt();
#if DEBUG_UNDUMP
Console.WriteLine( "LoadCode n:" + n );
#endif
proto.Code.Clear();
for( int i=0; i