Merge pull request #84 from dscho/random-access-file

Write support for the RandomAccessFile
This commit is contained in:
Joshua Warner 2013-10-21 09:38:44 -07:00
commit 02e433ce61
5 changed files with 193 additions and 24 deletions

View File

@ -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<uint8_t*>
@ -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<uint8_t*>
@ -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<uint8_t*>
(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<uint8_t*>
(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)
{

View File

@ -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;
}
};
}
}

View File

@ -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 {
}

View File

@ -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;
}
}

View File

@ -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;
}