Implemented issue: #56
This commit is contained in:
@@ -83,20 +83,15 @@ public class JmeIoLib extends IoLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
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;
|
String url = "file:///" + filename;
|
||||||
int mode = readMode? Connector.READ: Connector.READ_WRITE;
|
int mode = readMode? Connector.READ: Connector.READ_WRITE;
|
||||||
StreamConnection conn = (StreamConnection) Connector.open( url, mode );
|
StreamConnection conn = (StreamConnection) Connector.open( url, mode );
|
||||||
File f = readMode?
|
File f = readMode?
|
||||||
new FileImpl(conn, conn.openInputStream(), null):
|
new FileImpl(conn, conn.openInputStream(), null):
|
||||||
new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
|
new FileImpl(conn, null, conn.openOutputStream());
|
||||||
/*
|
|
||||||
if ( appendMode ) {
|
|
||||||
f.seek("end",0);
|
|
||||||
} else {
|
|
||||||
if ( ! readMode )
|
|
||||||
conn.truncate(0);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -84,14 +84,14 @@ public class JseIoLib extends IoLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
|
||||||
RandomAccessFile f = new RandomAccessFile(filename,readMode? "r": "rw");
|
RandomAccessFile f = new RandomAccessFile(filename, readMode && !updateMode ? "r": "rw");
|
||||||
if ( appendMode ) {
|
if ( appendMode ) {
|
||||||
f.seek(f.length());
|
f.seek(f.length());
|
||||||
} else {
|
} else {
|
||||||
if ( ! readMode )
|
if ( ! readMode )
|
||||||
f.setLength(0);
|
f.setLength(0);
|
||||||
}
|
}
|
||||||
return new FileImpl( f );
|
return new FileImpl( f, readMode || updateMode, !readMode || updateMode, appendMode );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected File openProgram(String prog, String mode) throws IOException {
|
protected File openProgram(String prog, String mode) throws IOException {
|
||||||
@@ -104,7 +104,7 @@ public class JseIoLib extends IoLib {
|
|||||||
protected File tmpFile() throws IOException {
|
protected File tmpFile() throws IOException {
|
||||||
java.io.File f = java.io.File.createTempFile(".luaj","bin");
|
java.io.File f = java.io.File.createTempFile(".luaj","bin");
|
||||||
f.deleteOnExit();
|
f.deleteOnExit();
|
||||||
return new FileImpl( new RandomAccessFile(f,"rw") );
|
return new FileImpl( new RandomAccessFile(f,"rw"), true, true, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void notimplemented() {
|
private static void notimplemented() {
|
||||||
@@ -116,21 +116,27 @@ public class JseIoLib extends IoLib {
|
|||||||
private final RandomAccessFile file;
|
private final RandomAccessFile file;
|
||||||
private final InputStream is;
|
private final InputStream is;
|
||||||
private final OutputStream os;
|
private final OutputStream os;
|
||||||
|
private final boolean readable;
|
||||||
|
private final boolean writable;
|
||||||
|
private final boolean append;
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
private boolean nobuffer = false;
|
private boolean nobuffer = false;
|
||||||
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
|
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os, boolean readable, boolean writable, boolean append ) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
|
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
|
||||||
this.os = os;
|
this.os = os;
|
||||||
|
this.readable = readable;
|
||||||
|
this.writable = writable;
|
||||||
|
this.append = append;
|
||||||
}
|
}
|
||||||
private FileImpl( RandomAccessFile f ) {
|
private FileImpl( RandomAccessFile f, boolean readable, boolean writable, boolean append ) {
|
||||||
this( f, null, null );
|
this( f, null, null, readable, writable, append );
|
||||||
}
|
}
|
||||||
private FileImpl( InputStream i ) {
|
private FileImpl( InputStream i ) {
|
||||||
this( null, i, null );
|
this( null, i, null, true, false, false );
|
||||||
}
|
}
|
||||||
private FileImpl( OutputStream o ) {
|
private FileImpl( OutputStream o ) {
|
||||||
this( null, null, o );
|
this( null, null, o, false, true, false );
|
||||||
}
|
}
|
||||||
public String tojstring() {
|
public String tojstring() {
|
||||||
return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
|
return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
|
||||||
@@ -149,11 +155,15 @@ public class JseIoLib extends IoLib {
|
|||||||
os.flush();
|
os.flush();
|
||||||
}
|
}
|
||||||
public void write(LuaString s) throws IOException {
|
public void write(LuaString s) throws IOException {
|
||||||
|
if ( ! writable )
|
||||||
|
throw new IOException("file is not writable");
|
||||||
if ( os != null )
|
if ( os != null )
|
||||||
os.write( s.m_bytes, s.m_offset, s.m_length );
|
os.write( s.m_bytes, s.m_offset, s.m_length );
|
||||||
else if ( file != null )
|
else if ( file != null ) {
|
||||||
|
if ( append )
|
||||||
|
file.seek(file.length());
|
||||||
file.write( s.m_bytes, s.m_offset, s.m_length );
|
file.write( s.m_bytes, s.m_offset, s.m_length );
|
||||||
else
|
} else
|
||||||
notimplemented();
|
notimplemented();
|
||||||
if ( nobuffer )
|
if ( nobuffer )
|
||||||
flush();
|
flush();
|
||||||
@@ -181,11 +191,15 @@ public class JseIoLib extends IoLib {
|
|||||||
|
|
||||||
// get length remaining to read
|
// get length remaining to read
|
||||||
public int remaining() throws IOException {
|
public int remaining() throws IOException {
|
||||||
|
if ( ! readable )
|
||||||
|
throw new IOException("file is not readable");
|
||||||
return file!=null? (int) (file.length()-file.getFilePointer()): -1;
|
return file!=null? (int) (file.length()-file.getFilePointer()): -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// peek ahead one character
|
// peek ahead one character
|
||||||
public int peek() throws IOException {
|
public int peek() throws IOException {
|
||||||
|
if ( ! readable )
|
||||||
|
throw new IOException("file is not readable");
|
||||||
if ( is != null ) {
|
if ( is != null ) {
|
||||||
is.mark(1);
|
is.mark(1);
|
||||||
int c = is.read();
|
int c = is.read();
|
||||||
@@ -203,6 +217,8 @@ public class JseIoLib extends IoLib {
|
|||||||
|
|
||||||
// return char if read, -1 if eof, throw IOException on other exception
|
// return char if read, -1 if eof, throw IOException on other exception
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
|
if ( ! readable )
|
||||||
|
throw new IOException("file is not readable");
|
||||||
if ( is != null )
|
if ( is != null )
|
||||||
return is.read();
|
return is.read();
|
||||||
else if ( file != null ) {
|
else if ( file != null ) {
|
||||||
@@ -214,6 +230,8 @@ public class JseIoLib extends IoLib {
|
|||||||
|
|
||||||
// return number of bytes read if positive, -1 if eof, throws IOException
|
// return number of bytes read if positive, -1 if eof, throws IOException
|
||||||
public int read(byte[] bytes, int offset, int length) throws IOException {
|
public int read(byte[] bytes, int offset, int length) throws IOException {
|
||||||
|
if ( ! readable )
|
||||||
|
throw new IOException("file is not readable");
|
||||||
if (file!=null) {
|
if (file!=null) {
|
||||||
return file.read(bytes, offset, length);
|
return file.read(bytes, offset, length);
|
||||||
} else if (is!=null) {
|
} else if (is!=null) {
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.luaj.vm2;
|
package org.luaj.vm2;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -236,6 +239,98 @@ public class FragmentsTest extends TestSuite {
|
|||||||
runFragment(LuaValue.valueOf(7), "return 1 | 2 & 6\n");
|
runFragment(LuaValue.valueOf(7), "return 1 | 2 & 6\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testIoOpenReadModeDisallowsWrite() throws Exception {
|
||||||
|
File file = writeTempFile("read-mode", "hello");
|
||||||
|
try {
|
||||||
|
Globals globals = JsePlatform.standardGlobals();
|
||||||
|
try {
|
||||||
|
globals.load("local f = io.open(" + quote(file.getAbsolutePath()) + ", 'r') f:write('x')", "io_r.lua").call();
|
||||||
|
fail("expected write on read-only file to fail");
|
||||||
|
} catch (LuaError e) {
|
||||||
|
assertTrue(e.getMessage().indexOf("not writable") >= 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() {
|
public void testTableMove() {
|
||||||
runFragment(
|
runFragment(
|
||||||
LuaValue.varargsOf(new LuaValue[] {
|
LuaValue.varargsOf(new LuaValue[] {
|
||||||
@@ -844,5 +939,20 @@ public class FragmentsTest extends TestSuite {
|
|||||||
+ "return v1, v2, v3");
|
+ "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("'", "\\'") + "'";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user