diff --git a/classlib/src/main/java/org/teavm/classlib/fs/VirtualFileAccessor.java b/classlib/src/main/java/org/teavm/classlib/fs/VirtualFileAccessor.java index a429587b9..531778e14 100644 --- a/classlib/src/main/java/org/teavm/classlib/fs/VirtualFileAccessor.java +++ b/classlib/src/main/java/org/teavm/classlib/fs/VirtualFileAccessor.java @@ -18,9 +18,15 @@ package org.teavm.classlib.fs; import java.io.IOException; public interface VirtualFileAccessor { - int read(int pos, byte[] buffer, int offset, int limit) throws IOException; + int read(byte[] buffer, int offset, int limit) throws IOException; - void write(int pos, byte[] buffer, int offset, int limit) throws IOException; + void write(byte[] buffer, int offset, int limit) throws IOException; + + int tell() throws IOException; + + void seek(int target) throws IOException; + + void skip(int amount) throws IOException; int size() throws IOException; diff --git a/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFile.java b/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFile.java index 796b511a4..98f7cce61 100644 --- a/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFile.java +++ b/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFile.java @@ -100,7 +100,7 @@ public class CVirtualFile implements VirtualFile { if (file == 0) { return null; } - return new CVirtualFileAccessor(file, append ? -1 : 0); + return new CVirtualFileAccessor(file); } @Override diff --git a/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFileAccessor.java b/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFileAccessor.java index fce1842eb..fb68bcf6d 100644 --- a/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFileAccessor.java +++ b/classlib/src/main/java/org/teavm/classlib/fs/c/CVirtualFileAccessor.java @@ -20,38 +20,50 @@ import org.teavm.classlib.fs.VirtualFileAccessor; public class CVirtualFileAccessor implements VirtualFileAccessor { private long file; - private int position; - public CVirtualFileAccessor(long file, int position) { + public CVirtualFileAccessor(long file) { this.file = file; - this.position = position; } @Override - public int read(int pos, byte[] buffer, int offset, int limit) throws IOException { - ensurePosition(pos); - int bytesRead = CFileSystem.read(file, buffer, offset, limit); - position += bytesRead; - return bytesRead; + public int read(byte[] buffer, int offset, int limit) throws IOException { + return CFileSystem.read(file, buffer, offset, limit); } @Override - public void write(int pos, byte[] buffer, int offset, int limit) throws IOException { - ensurePosition(pos); + public void write(byte[] buffer, int offset, int limit) throws IOException { int bytesWritten = CFileSystem.write(file, buffer, offset, limit); if (bytesWritten < limit) { throw new IOException(); } - position += bytesWritten; + } + + @Override + public int tell() throws IOException { + return CFileSystem.tell(file); + } + + @Override + public void skip(int amount) throws IOException { + CFileSystem.seek(file, 0, amount); + } + + @Override + public void seek(int target) throws IOException { + CFileSystem.seek(file, 0, target); } @Override public int size() throws IOException { + int current = CFileSystem.tell(file); if (!CFileSystem.seek(file, 2, 0)) { throw new IOException(); } - position = CFileSystem.tell(file); - return position; + int result = CFileSystem.tell(file); + if (!CFileSystem.seek(file, 0, current)) { + throw new IOException(); + } + return result; } @Override @@ -59,11 +71,13 @@ public class CVirtualFileAccessor implements VirtualFileAccessor { if (!CFileSystem.seek(file, 2, 0)) { throw new IOException(); } - position = CFileSystem.tell(file); + int position = CFileSystem.tell(file); if (position < size) { byte[] zeros = new byte[4096]; while (position < size) { - write(position, zeros, 0, Math.min(zeros.length, size - position)); + int bytesToWrite = Math.min(zeros.length, size - position); + write(zeros, 0, bytesToWrite); + position += bytesToWrite; } } } @@ -83,13 +97,4 @@ public class CVirtualFileAccessor implements VirtualFileAccessor { throw new IOException(); } } - - private void ensurePosition(int pos) throws IOException { - if (position != pos) { - if (!CFileSystem.seek(file, 0, pos)) { - throw new IOException(); - } - position = pos; - } - } } diff --git a/classlib/src/main/java/org/teavm/classlib/fs/memory/InMemoryVirtualFile.java b/classlib/src/main/java/org/teavm/classlib/fs/memory/InMemoryVirtualFile.java index 0f9dc31f8..fb23ca779 100644 --- a/classlib/src/main/java/org/teavm/classlib/fs/memory/InMemoryVirtualFile.java +++ b/classlib/src/main/java/org/teavm/classlib/fs/memory/InMemoryVirtualFile.java @@ -58,21 +58,50 @@ public class InMemoryVirtualFile extends AbstractInMemoryVirtualFile { } return new VirtualFileAccessor() { + private int pos; + + { + if (append) { + pos = size; + } + } + @Override - public int read(int pos, byte[] buffer, int offset, int limit) { + public int read(byte[] buffer, int offset, int limit) { limit = Math.max(0, Math.min(size - pos, limit)); - System.arraycopy(data, pos, buffer, offset, limit); + if (limit > 0) { + System.arraycopy(data, pos, buffer, offset, limit); + pos += limit; + } return limit; } @Override - public void write(int pos, byte[] buffer, int offset, int limit) { + public void write(byte[] buffer, int offset, int limit) { expandData(pos + limit); System.arraycopy(buffer, offset, data, pos, limit); - size = pos + limit; + pos += limit; + if (pos > size) { + size = pos; + } modify(); } + @Override + public int tell() throws IOException { + return pos; + } + + @Override + public void seek(int target) throws IOException { + pos = target; + } + + @Override + public void skip(int amount) throws IOException { + pos += amount; + } + @Override public int size() { return size; diff --git a/classlib/src/main/java/org/teavm/classlib/java/io/TFileInputStream.java b/classlib/src/main/java/org/teavm/classlib/java/io/TFileInputStream.java index 9e4dab949..e847bf595 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/io/TFileInputStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/io/TFileInputStream.java @@ -23,9 +23,8 @@ import org.teavm.classlib.fs.VirtualFile; import org.teavm.classlib.fs.VirtualFileAccessor; public class TFileInputStream extends InputStream { + private static final byte[] ONE_BYTE_BUFFER = new byte[1]; private VirtualFileAccessor accessor; - private int pos; - private boolean eof; public TFileInputStream(TFile file) throws FileNotFoundException { VirtualFile virtualFile = file.findVirtualFile(); @@ -52,16 +51,9 @@ public class TFileInputStream extends InputStream { if (len == 0) { return 0; } - if (eof) { - return -1; - } ensureOpened(); - int result = accessor.read(pos, b, off, len); - pos += result; - if (pos == accessor.size()) { - eof = true; - } - return result; + int result = accessor.read(b, off, len); + return result > 0 ? result : -1; } @Override @@ -70,25 +62,20 @@ public class TFileInputStream extends InputStream { throw new IOException("Value must be positive: " + n); } ensureOpened(); - if (eof) { - return 0; + int last = accessor.tell(); + accessor.skip((int) n - 1); + if (accessor.read(ONE_BYTE_BUFFER, 0, 1) < 1) { + int position = accessor.size(); + accessor.seek(position); + return position - last; } - int newPos = Math.max(pos, Math.min(accessor.size(), pos + (int) n)); - int result = newPos - pos; - pos = newPos; - if (result == 0) { - eof = true; - } - return result; + return n; } @Override public int available() throws IOException { ensureOpened(); - if (eof) { - return 0; - } - return Math.max(0, accessor.size() - pos); + return Math.max(0, accessor.size() - accessor.tell()); } @Override @@ -102,17 +89,9 @@ public class TFileInputStream extends InputStream { @Override public int read() throws IOException { ensureOpened(); - if (eof) { - return -1; - } - byte[] buffer = new byte[1]; - int read = accessor.read(pos, buffer, 0, 1); - if (read == 0) { - eof = true; - } else { - pos++; - } - return !eof ? buffer[0] : -1; + byte[] buffer = ONE_BYTE_BUFFER; + int read = accessor.read(buffer, 0, 1); + return read != 0 ? buffer[0] : -1; } private void ensureOpened() throws IOException { diff --git a/classlib/src/main/java/org/teavm/classlib/java/io/TFileOutputStream.java b/classlib/src/main/java/org/teavm/classlib/java/io/TFileOutputStream.java index 0a0e8f963..20187534f 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/io/TFileOutputStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/io/TFileOutputStream.java @@ -24,8 +24,8 @@ import org.teavm.classlib.fs.VirtualFile; import org.teavm.classlib.fs.VirtualFileAccessor; public class TFileOutputStream extends OutputStream { + private static byte[] ONE_BYTE_BUFER = new byte[1]; private VirtualFileAccessor accessor; - private int pos; public TFileOutputStream(TFile file) throws FileNotFoundException { this(file, false); @@ -57,10 +57,6 @@ public class TFileOutputStream extends OutputStream { if (accessor == null) { throw new FileNotFoundException(); } - - if (append) { - pos = -1; - } } @Override @@ -69,9 +65,8 @@ public class TFileOutputStream extends OutputStream { if (off < 0 || len < 0 || off > b.length - len) { throw new IndexOutOfBoundsException(); } - ensurePos(); - accessor.write(pos, b, off, len); - pos += len; + ensureOpened(); + accessor.write(b, off, len); } @Override @@ -90,10 +85,10 @@ public class TFileOutputStream extends OutputStream { @Override public void write(int b) throws IOException { - ensurePos(); - byte[] buffer = { (byte) b }; - accessor.write(pos, buffer, 0, 1); - pos++; + ensureOpened(); + byte[] buffer = ONE_BYTE_BUFER; + buffer[0] = (byte) b; + accessor.write(buffer, 0, 1); } private void ensureOpened() throws IOException { @@ -101,11 +96,4 @@ public class TFileOutputStream extends OutputStream { throw new IOException("This stream is already closed"); } } - - private void ensurePos() throws IOException { - ensureOpened(); - if (pos < 0) { - pos = accessor.size(); - } - } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/io/TRandomAccessFile.java b/classlib/src/main/java/org/teavm/classlib/java/io/TRandomAccessFile.java index 69923ea95..518d73df6 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/io/TRandomAccessFile.java +++ b/classlib/src/main/java/org/teavm/classlib/java/io/TRandomAccessFile.java @@ -29,10 +29,10 @@ import org.teavm.classlib.java.lang.TIndexOutOfBoundsException; import org.teavm.classlib.java.lang.TNullPointerException; public class TRandomAccessFile implements DataInput, DataOutput, Closeable { + private static final byte[] ONE_BYTE_BUFFER = new byte[1]; private boolean readOnly; private boolean autoFlush; private VirtualFileAccessor accessor; - private int pos; private byte[] buff; public TRandomAccessFile(String name, String mode) throws FileNotFoundException { @@ -76,13 +76,9 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable { if (off < 0 || len < 0 || off + len > b.length) { throw new IndexOutOfBoundsException(); } - if (pos >= accessor.size()) { - return -1; - } ensureOpened(); - int result = accessor.read(pos, b, off, len); - pos += result; - return result; + int result = accessor.read(b, off, len); + return result > 0 ? result : -1; } public int read(byte[] b) throws IOException { @@ -92,8 +88,7 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable { public int read() throws IOException { ensureOpened(); byte[] buffer = new byte[1]; - int read = accessor.read(pos, buffer, 0, 1); - pos += read; + int read = accessor.read(buffer, 0, 1); return read > 0 ? buffer[0] : -1; } @@ -134,20 +129,24 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable { public int skipBytes(int n) throws IOException { ensureOpened(); - int newPos = Math.max(pos, Math.min(accessor.size(), pos)); - int result = newPos - pos; - pos = newPos; - return result; + int last = accessor.tell(); + accessor.skip(n - 1); + if (accessor.read(ONE_BYTE_BUFFER, 0, 1) < 1) { + int position = accessor.size(); + accessor.seek(position); + return position - last; + } + return n; } public long getFilePointer() throws IOException { ensureOpened(); - return pos; + return accessor.tell(); } public void seek(long pos) throws IOException { ensureOpened(); - this.pos = (int) pos; + accessor.seek((int) pos); } public long length() throws IOException { @@ -287,11 +286,10 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable { public void write(int b) throws IOException { ensureOpened(); byte[] buffer = { (byte) b }; - accessor.write(pos, buffer, 0, 1); + accessor.write(buffer, 0, 1); if (autoFlush) { accessor.flush(); } - pos++; } @Override @@ -306,11 +304,10 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable { throw new IndexOutOfBoundsException(); } ensureOpened(); - accessor.write(pos, b, off, len); + accessor.write(b, off, len); if (autoFlush) { accessor.flush(); } - pos += len; } @Override diff --git a/core/src/main/resources/org/teavm/backend/c/file.c b/core/src/main/resources/org/teavm/backend/c/file.c index 2b9c52545..55cdd735f 100644 --- a/core/src/main/resources/org/teavm/backend/c/file.c +++ b/core/src/main/resources/org/teavm/backend/c/file.c @@ -566,7 +566,7 @@ int32_t teavm_file_flush(int64_t file) { } int32_t teavm_file_seek(int64_t file, int32_t where, int32_t offset) { - return SetFilePointer((HANDLE) file, offset, 0, where); + return SetFilePointer((HANDLE) file, offset, 0, where) != INVALID_SET_FILE_POINTER; } int32_t teavm_file_tell(int64_t file) {