ちょっと怖いですね。
背景情報として、いくつかの lua モジュールを含む tar アーカイブを、LuaInterface を使用して C# アプリケーションにロードしたいと考えています。最も簡単な方法は、これらのファイルを一時フォルダーに抽出し、lua モジュールの検索パスを変更して、require で通常どおり読み取ることです。しかし、これらのスクリプトをファイル システムのどこかに置きたくありません。
だから私は#ziplibで tar アーカイブをロードできるはずだと思った。しかし、#zlib はすでにプロジェクトの一部です。
アーカイブからファイルを文字列 (ストリーム) として正常にロードした後、LuaInterface 経由で C# の lua.DoString(...) に渡すことができるはずです。
しかし、モジュールに「module(..., package.seeall)」のような行がある場合、dostring または dofile によってモジュールをロードするだけでは機能しません。
もう 1 つの問題は、モジュールが tar アーカイブにある他のモジュールに依存している可能性があることです。
考えられる解決策の 1 つは、ここで説明されているようにカスタム ローダーを定義することです。
私の考えは、#ziplib を使用して C# でそのようなローダーを実装し、このローダーを C# アプリケーションの lua スタックにマップすることです。
これと同じような仕事をした人はいますか?このような問題にすでに対処している、すぐに使用できるソリューションはありますか?
tar ファイルは必須ではありませんが、あると便利なパッケージ形式です。
このアイデアは実現可能ですか、それとも完全に不可能ですか?
アーカイブから lua ファイルを抽出するクラスの例をいくつか書きました。このメソッドはローダーとして機能し、lua 関数を返します。
namespace LuaInterfaceTest
{
class LuaTarModuleLoader
{
private LuaTarModuleLoader() { }
~LuaTarModuleLoader()
{
in_stream_.Close();
}
public LuaTarModuleLoader(Stream in_stream,Lua lua )
{
in_stream_ = in_stream;
lua_ = lua;
}
public LuaFunction load(string modulename, out string error_message)
{
string lua_chunk = "test=hello";
string filename = modulename + ".lua";
error_message = "Unable to locate the file";
in_stream_.Position = 0; // rewind
Stream gzipStream = new BZip2InputStream(in_stream_);
TarInputStream tar = new TarInputStream(gzipStream);
TarEntry tarEntry;
LuaFunction func = null;
while ((tarEntry = tar.GetNextEntry()) != null)
{
if (tarEntry.IsDirectory)
{
continue;
}
if (filename == tarEntry.Name)
{
MemoryStream out_stream = new MemoryStream();
tar.CopyEntryContents(out_stream);
out_stream.Position = 0; // rewind
StreamReader stream_reader = new StreamReader(out_stream);
lua_chunk = stream_reader.ReadToEnd();
func = lua_.LoadString(lua_chunk, filename);
string dum = func.ToString();
error_message = "No Error!";
break;
}
}
return func;
}
private Stream in_stream_;
private Lua lua_;
}
}
LuaInterface にこのような load メソッドを登録してみる
Lua lua = new Lua();
GC.Collect();
Stream inStream = File.OpenRead("c:\\tmp\\lua_scripts.tar.bz2");
LuaTarModuleLoader tar_loader = new LuaTarModuleLoader(inStream, lua);
lua.DoString("require 'CLRPackage'");
lua.DoString("import \"ICSharpCode.SharpZipLib.dll\"");
lua.DoString("import \"System\"");
lua["container_module_loader"] = tar_loader;
lua.DoString("table.insert(package.loaders, 2, container_module_loader.load)");
lua.DoString("require 'def_sensor'");
この方法で試してみると、 require の呼び出し中に例外が発生します。
「インスタンス メソッド 'load' には、null 以外のターゲット オブジェクトが必要です」
load メソッドを直接呼び出そうとしましたが、ここでは ":" 表記を使用する必要があります。
lua.DoString("container_module_loader:load('def_sensor')");
そのようなメソッドを呼び出すと、メソッドの上にあるデバッガーのブレークポイントにヒットするため、すべてが期待どおりに機能します。
しかし、「:」表記でメソッドを登録しようとすると、メソッドの登録中に例外が発生します。
lua.DoString("table.insert(package.loaders, 2, container_module_loader:load)");
"[string "chunk"]:1: ')' の近くに関数の引数が必要です"