diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index c8a0c8419f..083df06133 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -619,7 +619,7 @@ Java_java_io_File_openDir(JNIEnv* e, jclass, jstring path) #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) d->handle = FindFirstFileW(RUNTIME_ARRAY_BODY(buffer), &(d->data)); #else - d->handle = FindFirstFileExW(RUNTIME_ARRAY_BODY(buffer), FindExInfoStandard, &(d->data), FindExSearchNameMatch, NULL, 0); + d->handle = FindFirstFileExW(RUNTIME_ARRAY_BODY(buffer), FindExInfoStandard, &(d->data), FindExSearchNameMatch, NULL, 0); #endif if (d->handle == INVALID_HANDLE_VALUE) { d->dispose(); @@ -803,28 +803,29 @@ Java_java_io_FileOutputStream_close(JNIEnv* e, jclass, jint fd) extern "C" JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_open(JNIEnv* e, jclass, jstring path, - jlongArray result) + jboolean allowWrite, jlongArray result) { string_t chars = getChars(e, path); if (chars) { jlong peer = 0; jlong length = 0; + int flags = (allowWrite ? O_RDWR | O_CREAT : O_RDONLY) | OPEN_MASK; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #if defined(PLATFORM_WINDOWS) - int fd = ::_wopen(chars, O_RDONLY | OPEN_MASK); + int fd = ::_wopen(chars, flags); #else - int fd = ::open((const char*)chars, O_RDONLY | OPEN_MASK); + int fd = ::open((const char*)chars, flags, 0644); #endif - releaseChars(e, path, chars); - if (fd == -1) { + releaseChars(e, path, chars); + if (fd == -1) { throwNewErrno(e, "java/io/IOException"); - return; + return; } - struct ::stat fileStats; - if(::fstat(fd, &fileStats) == -1) { - ::close(fd); + struct ::stat fileStats; + if(::fstat(fd, &fileStats) == -1) { + ::close(fd); throwNewErrno(e, "java/io/IOException"); - return; + return; } peer = fd; length = fileStats.st_size; @@ -860,8 +861,8 @@ Java_java_io_RandomAccessFile_readBytes(JNIEnv* e, jclass, jlong peer, #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) int fd = (int)peer; if(::lseek(fd, position, SEEK_SET) == -1) { - throwNewErrno(e, "java/io/IOException"); - return -1; + throwNewErrno(e, "java/io/IOException"); + return -1; } uint8_t* dst = reinterpret_cast @@ -871,16 +872,16 @@ Java_java_io_RandomAccessFile_readBytes(JNIEnv* e, jclass, jlong peer, e->ReleasePrimitiveArrayCritical(buffer, dst, 0); if(bytesRead == -1) { - throwNewErrno(e, "java/io/IOException"); - return -1; + throwNewErrno(e, "java/io/IOException"); + return -1; } #else HANDLE hFile = (HANDLE)peer; LARGE_INTEGER lPos; lPos.QuadPart = position; if(!SetFilePointerEx(hFile, lPos, nullptr, FILE_BEGIN)) { - throwNewErrno(e, "java/io/IOException"); - return -1; + throwNewErrno(e, "java/io/IOException"); + return -1; } uint8_t* dst = reinterpret_cast @@ -888,8 +889,9 @@ Java_java_io_RandomAccessFile_readBytes(JNIEnv* e, jclass, jlong peer, DWORD bytesRead = 0; if(!ReadFile(hFile, dst + offset, length, &bytesRead, nullptr)) { - throwNewErrno(e, "java/io/IOException"); - return -1; + e->ReleasePrimitiveArrayCritical(buffer, dst, 0); + throwNewErrno(e, "java/io/IOException"); + return -1; } e->ReleasePrimitiveArrayCritical(buffer, dst, 0); #endif @@ -897,6 +899,52 @@ Java_java_io_RandomAccessFile_readBytes(JNIEnv* e, jclass, jlong peer, return (jint)bytesRead; } +extern "C" JNIEXPORT jint JNICALL +Java_java_io_RandomAccessFile_writeBytes(JNIEnv* e, jclass, jlong peer, + jlong position, jbyteArray buffer, + int offset, int length) +{ +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + int fd = (int)peer; + if(::lseek(fd, position, SEEK_SET) == -1) { + throwNewErrno(e, "java/io/IOException"); + return -1; + } + + uint8_t* dst = reinterpret_cast + (e->GetPrimitiveArrayCritical(buffer, 0)); + + int64_t bytesWritten = ::write(fd, dst + offset, length); + e->ReleasePrimitiveArrayCritical(buffer, dst, 0); + + if(bytesWritten == -1) { + throwNewErrno(e, "java/io/IOException"); + return -1; + } +#else + HANDLE hFile = (HANDLE)peer; + LARGE_INTEGER lPos; + lPos.QuadPart = position; + if(!SetFilePointerEx(hFile, lPos, nullptr, FILE_BEGIN)) { + throwNewErrno(e, "java/io/IOException"); + return -1; + } + + uint8_t* dst = reinterpret_cast + (e->GetPrimitiveArrayCritical(buffer, 0)); + + DWORD bytesWritten = 0; + if(!WriteFile(hFile, dst + offset, length, &bytesWritten, nullptr)) { + e->ReleasePrimitiveArrayCritical(buffer, dst, 0); + throwNewErrno(e, "java/io/IOException"); + return -1; + } + e->ReleasePrimitiveArrayCritical(buffer, dst, 0); +#endif + + return (jint)bytesWritten; +} + extern "C" JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_close(JNIEnv* /* e*/, jclass, jlong peer) { diff --git a/classpath/java/io/RandomAccessFile.java b/classpath/java/io/RandomAccessFile.java index aeedbd460c..f411bbe748 100644 --- a/classpath/java/io/RandomAccessFile.java +++ b/classpath/java/io/RandomAccessFile.java @@ -11,29 +11,40 @@ package java.io; import java.lang.IllegalArgumentException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; public class RandomAccessFile { private long peer; private File file; private long position = 0; private long length; + private boolean allowWrite; public RandomAccessFile(String name, String mode) throws FileNotFoundException { - if (! mode.equals("r")) throw new IllegalArgumentException(); - file = new File(name); + this(new File(name), mode); + } + + public RandomAccessFile(File file, String mode) + throws FileNotFoundException + { + if (file == null) throw new NullPointerException(); + if (mode.equals("rw")) allowWrite = true; + else if (! mode.equals("r")) throw new IllegalArgumentException(); + this.file = file; open(); } private void open() throws FileNotFoundException { long[] result = new long[2]; - open(file.getPath(), result); + open(file.getPath(), allowWrite, result); peer = result[0]; length = result[1]; } - private static native void open(String name, long[] result) + private static native void open(String name, boolean allowWrite, long[] result) throws FileNotFoundException; private void refresh() throws IOException { @@ -53,7 +64,7 @@ public class RandomAccessFile { } public void seek(long position) throws IOException { - if (position < 0 || position > length()) throw new IOException(); + if (position < 0 || (!allowWrite && position > length())) throw new IOException(); this.position = position; } @@ -122,6 +133,14 @@ public class RandomAccessFile { private static native int readBytes(long peer, long position, byte[] buffer, int offset, int length); + public void write(int b) throws IOException { + int count = writeBytes(peer, position, new byte[] { (byte)b }, 0, 1); + if (count > 0) position += count; + } + + private static native int writeBytes(long peer, long position, byte[] buffer, + int offset, int length); + public void close() throws IOException { if (peer != 0) { close(peer); @@ -130,4 +149,50 @@ public class RandomAccessFile { } private static native void close(long peer); + + public FileChannel getChannel() { + return new FileChannel() { + public void close() { + if (peer != 0) RandomAccessFile.close(peer); + } + + public boolean isOpen() { + return peer != 0; + } + + public int read(ByteBuffer dst, long position) throws IOException { + if (!dst.hasArray()) throw new IOException("Cannot handle " + dst.getClass()); + // TODO: this needs to be synchronized on the Buffer, no? + byte[] array = dst.array(); + return readBytes(peer, position, array, dst.position(), dst.remaining()); + } + + public int read(ByteBuffer dst) throws IOException { + int count = read(dst, position); + if (count > 0) position += count; + return count; + } + + public int write(ByteBuffer src, long position) throws IOException { + if (!src.hasArray()) throw new IOException("Cannot handle " + src.getClass()); + byte[] array = src.array(); + return writeBytes(peer, position, array, src.position(), src.remaining()); + } + + public int write(ByteBuffer src) throws IOException { + int count = write(src, position); + if (count > 0) position += count; + return count; + } + + public long position() throws IOException { + return getFilePointer(); + } + + public FileChannel position(long position) throws IOException { + seek(position); + return this; + } + }; + } } diff --git a/classpath/java/nio/BufferUnderflowException.java b/classpath/java/nio/BufferUnderflowException.java new file mode 100644 index 0000000000..d8b6a6fe88 --- /dev/null +++ b/classpath/java/nio/BufferUnderflowException.java @@ -0,0 +1,14 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.nio; + +public class BufferUnderflowException extends RuntimeException { +} diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index 71c3c7f09a..ee3767f7de 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -244,4 +244,13 @@ public abstract class ByteBuffer protected void checkGet(int position, int amount) { if (amount > limit-position) throw new IndexOutOfBoundsException(); } + + public ByteBuffer order(ByteOrder order) { + if (order != ByteOrder.BIG_ENDIAN) throw new UnsupportedOperationException(); + return this; + } + + public ByteOrder order() { + return ByteOrder.BIG_ENDIAN; + } } diff --git a/classpath/java/nio/channels/FileChannel.java b/classpath/java/nio/channels/FileChannel.java new file mode 100644 index 0000000000..e94641086a --- /dev/null +++ b/classpath/java/nio/channels/FileChannel.java @@ -0,0 +1,33 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public abstract class FileChannel implements Channel { + + public static enum MapMode { + PRIVATE, READ_ONLY, READ_WRITE + }; + + public abstract int read(ByteBuffer dst) throws IOException; + + public abstract int read(ByteBuffer dst, long position) throws IOException; + + public abstract int write(ByteBuffer dst) throws IOException; + + public abstract int write(ByteBuffer dst, long position) throws IOException; + + public abstract long position() throws IOException; + + public abstract FileChannel position(long position) throws IOException; +}