From 7aea99d650482ce38543787c940286499bf1daab Mon Sep 17 00:00:00 2001 From: UnlegitDqrk Date: Mon, 2 Mar 2026 14:58:31 +0100 Subject: [PATCH] Implemented issue: #56 --- .../java/org/luaj/vm2/libs/jme/JmeIoLib.java | 13 +-- .../luaj/vm2/libs/jse/JseIoLib$FileImpl.class | Bin 4016 -> 4424 bytes .../vm2/libs/jse/JseIoLib$StdinFile.class | Bin 2368 -> 2368 bytes .../vm2/libs/jse/JseIoLib$StdoutFile.class | Bin 2550 -> 2550 bytes .../java/org/luaj/vm2/libs/jse/JseIoLib.class | Bin 3037 -> 3274 bytes .../java/org/luaj/vm2/libs/jse/JseIoLib.java | 38 ++++-- .../test/java/org/luaj/vm2/FragmentsTest.java | 110 ++++++++++++++++++ 7 files changed, 142 insertions(+), 19 deletions(-) diff --git a/jme/src/main/java/org/luaj/vm2/libs/jme/JmeIoLib.java b/jme/src/main/java/org/luaj/vm2/libs/jme/JmeIoLib.java index 8c60a940..de6c8501 100644 --- a/jme/src/main/java/org/luaj/vm2/libs/jme/JmeIoLib.java +++ b/jme/src/main/java/org/luaj/vm2/libs/jme/JmeIoLib.java @@ -83,20 +83,15 @@ public class JmeIoLib extends IoLib { } protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException { + if ( appendMode || updateMode ) { + throw new IOException("unsupported mode"); + } String url = "file:///" + filename; int mode = readMode? Connector.READ: Connector.READ_WRITE; StreamConnection conn = (StreamConnection) Connector.open( url, mode ); File f = readMode? new FileImpl(conn, conn.openInputStream(), null): - new FileImpl(conn, conn.openInputStream(), conn.openOutputStream()); - /* - if ( appendMode ) { - f.seek("end",0); - } else { - if ( ! readMode ) - conn.truncate(0); - } - */ + new FileImpl(conn, null, conn.openOutputStream()); return f; } diff --git a/jse/src/main/java/org/luaj/vm2/libs/jse/JseIoLib$FileImpl.class b/jse/src/main/java/org/luaj/vm2/libs/jse/JseIoLib$FileImpl.class index 736d070cad89fc691305ff432d7fd1b5f750a8f7..c6e4f50539266b920a31d9a74f4fdd1a3c7d9159 100644 GIT binary patch literal 4424 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 diff --git a/jse/src/main/java/org/luaj/vm2/libs/jse/JseIoLib$StdinFile.class b/jse/src/main/java/org/luaj/vm2/libs/jse/JseIoLib$StdinFile.class index de1b21f68861b9b65eeef6ac8a057eea5a4d46e6..69eff34e9a75efc6bb103968b6b6b24679d6962d 100644 GIT binary patch delta 104 zcmX>gbU13#nLaumQ<%ARWOV#}LV&%@EC?&k)04 z$`Hp;!oa}D%E0xXL3pw%r*-{*27U&1b_OPP23tlTU}q3#VBuge1tPGZ_lc~^Xc0TZL`WJ4zF&G}5OY=R7H8CV$D85kI>cQc4bYRk-=e2T-scsqmc2A~)d zLl%&fVqgQ3;S8b-5e$+Hkql}K(F|G)F$@L_aSSCu83zWI{|tPSy*RBWdvQ(Uv= 0); + } + } finally { + file.delete(); + } + } + + public void testIoOpenWriteModeDisallowsRead() throws Exception { + File file = File.createTempFile("luaj-io", ".txt"); + try { + Globals globals = JsePlatform.standardGlobals(); + try { + globals.load("local f = io.open(" + quote(file.getAbsolutePath()) + ", 'w') return f:read('*a')", "io_w.lua").call(); + fail("expected read on write-only file to fail"); + } catch (LuaError e) { + assertTrue(e.getMessage().indexOf("not readable") >= 0); + } + } finally { + file.delete(); + } + } + + public void testIoOpenUpdateModesSupportReadWrite() throws Exception { + File file = writeTempFile("update-mode", "abc"); + try { + Globals globals = JsePlatform.standardGlobals(); + Varargs result = globals.load( + "local f = assert(io.open(" + quote(file.getAbsolutePath()) + ", 'r+'))\n" + + "local before = f:read('*a')\n" + + "f:seek('set', 0)\n" + + "f:write('xyz')\n" + + "f:seek('set', 0)\n" + + "local after = f:read('*a')\n" + + "f:close()\n" + + "return before, after\n", + "io_rplus.lua").invoke(); + assertEquals("abc", result.arg1().tojstring()); + assertEquals("xyz", result.arg(2).tojstring()); + } finally { + file.delete(); + } + } + + public void testIoOpenAppendPreservesExistingContent() throws Exception { + File file = writeTempFile("append-mode", "abc"); + try { + Globals globals = JsePlatform.standardGlobals(); + LuaValue result = globals.load( + "local f = assert(io.open(" + quote(file.getAbsolutePath()) + ", 'a'))\n" + + "f:write('xyz')\n" + + "f:close()\n" + + "local g = assert(io.open(" + quote(file.getAbsolutePath()) + ", 'r'))\n" + + "local contents = g:read('*a')\n" + + "g:close()\n" + + "return contents\n", + "io_a.lua").call(); + assertEquals("abcxyz", result.tojstring()); + } finally { + file.delete(); + } + } + + public void testIoOpenAppendUpdateAppendsOnWriteAfterSeek() throws Exception { + File file = writeTempFile("append-update", "abc"); + try { + Globals globals = JsePlatform.standardGlobals(); + Varargs result = globals.load( + "local f = assert(io.open(" + quote(file.getAbsolutePath()) + ", 'a+'))\n" + + "f:seek('set', 0)\n" + + "local before = f:read('*a')\n" + + "f:seek('set', 0)\n" + + "f:write('xyz')\n" + + "f:seek('set', 0)\n" + + "local after = f:read('*a')\n" + + "f:close()\n" + + "return before, after\n", + "io_aplus.lua").invoke(); + assertEquals("abc", result.arg1().tojstring()); + assertEquals("abcxyz", result.arg(2).tojstring()); + } finally { + file.delete(); + } + } + public void testTableMove() { runFragment( LuaValue.varargsOf(new LuaValue[] { @@ -844,5 +939,20 @@ public class FragmentsTest extends TestSuite { + "return v1, v2, v3"); } + + private static File writeTempFile(String prefix, String contents) throws IOException { + File file = File.createTempFile(prefix, ".txt"); + FileOutputStream out = new FileOutputStream(file); + try { + out.write(contents.getBytes("UTF-8")); + } finally { + out.close(); + } + return file; + } + + private static String quote(String value) { + return "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'"; + } } }