/*
* @(#)RandomAccessStream.java 1.20 02/08/27 @(#)
*
* Copyright (c) 2001-2002 Sun Microsystems, Inc. All rights reserved.
* PROPRIETARY/CONFIDENTIAL
* Use is subject to license terms.
*/
package com.sun.midp.io.j2me.storage;
import java.io.*;
import javax.microedition.io.Connector;
import com.sun.midp.midlet.Scheduler;
import com.sun.midp.midlet.MIDletSuite;
import com.sun.midp.security.SecurityToken;
import com.sun.midp.security.Permissions;
import com.sun.midp.io.ConnectionBaseAdapter;
import com.sun.midp.io.Util;
/** A secure storage file stream that can be repositioned. */
public class RandomAccessStream extends ConnectionBaseAdapter {
/** Signals the native code to open a truncated file for read-write. */
public static final int READ_WRITE_TRUNCATE = -(Connector.READ_WRITE);
/** Native file handle, set to -1 when not connected. */
private int handle = -1;
/** Constructs a RandomAccessStream. */
public RandomAccessStream() {
MIDletSuite midletSuite = Scheduler.getScheduler().getMIDletSuite();
// if a MIDlet suite is not scheduled, assume the JAM is calling.
if (midletSuite != null) {
midletSuite.checkIfPermissionAllowed(Permissions.MIDP);
}
};
/**
* Constructs a RandomAccess Stream for callers that have a
* different permissions than the currently running MIDlet suite.
*
* @param callerSecurityToken security token of the caller
*/
public RandomAccessStream(SecurityToken callerSecurityToken) {
callerSecurityToken.checkIfPermissionAllowed(Permissions.MIDP);
};
/**
* Connect to a file in storage.
*
* @param name The URL for the connection, without the
* without the protcol part.
* @param mode {@link javax.microedition.io.Connection} READ, WRITE,
* or READ_WRITE
* @param timeouts A flag to indicate that the called wants
* timeout exceptions, ignored
*
* @exception IllegalArgumentException If a parameter is invalid.
* @exception ConnectionNotFoundException If the connection cannot be
* found.
* @exception IOException If some other kind of I/O error occurs.
*/
public void connect(String name, int mode, boolean timeouts)
throws IOException {
connect(name, mode);
};
/**
* Called to connect a RandomAccessStream to a file in storage.
*
* @param name contains storage filename
* @param mode {@link javax.microedition.io.Connection} READ, WRITE,
* or READ_WRITE
* @exception IOException if an I/O error occurs
*/
public void connect(String name, int mode)
throws IOException {
byte[] asciiFilename;
if (handle != -1) {
throw new
IOException("Disconnect the stream before reconnecting.");
}
asciiFilename = Util.toCString(name);
handle = open(asciiFilename, mode);
/* This object is re-used by internal methods */
connectionOpen = true;
if (mode == Connector.READ) {
maxOStreams = 0;
} else {
maxOStreams = 1;
}
maxIStreams = 1;
};
/**
* Disconnect the stream.
* <p>
* Any streams obtained with either <code>openInputStream</code> or
* <code>openOutputStream</code> will throw an exception if used after
* this call.
*
* @exception IOException if an I/O error occurs when closing the
* connection.
*/
public void disconnect() throws IOException {
if (handle == -1) {
return;
}
close(handle);
handle = -1;
connectionOpen = false;
};
/**
* Reads up to <code>len</code> bytes of data from the input stream into
* an array of bytes, blocks until at least one byte is available.
* <p>
* Do not use this method if <code>openInputStream</code> has been called
* since the input stream may be buffering data.
*
* @param b the buffer into which the data is read.
* @param off the start offset in array <code>b</code>
* at which the data is written.
* @param len the maximum number of bytes to read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
public int readBytes(byte b[], int off, int len) throws IOException {
if (len == 0) {
return 0;
}
// test before we goto the native code
int test = b[off] + b[len - 1] + b[off + len - 1];
return read(handle, b, off, len);
};
/**
* Reads up to <code>len</code> bytes of data from the input stream into
* an array of bytes, but does not block if no bytes available.
* <p>
* The <code>readBytesNonBlocking</code> method of
* <code>ConnectionBaseAdapter</code> does nothing and returns 0.
*
* @param b the buffer into which the data is read.
* @param off the start offset in array <code>b</code>
* at which the data is written.
* @param len the maximum number of bytes to read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
protected int readBytesNonBlocking(byte b[], int off, int len)
throws IOException {
// Read bytes should be non blocking
return readBytes(b, off, len);
};
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this output stream.
* <p>
* Polling the native code is done here to allow for simple
* asynchronous native code to be written. Not all implementations
* work this way (they block in the native code) but the same
* Java code works for both.
* <p>
* Do not use this method if <code>openOutputStream</code> has been called
* since the output stream may be buffering data.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @return number of bytes written
* @exception IOException if an I/O error occurs. In particular,
* an <code>IOException</code> is thrown if the output
* stream is closed.
*/
public int writeBytes(byte b[], int off, int len) throws IOException {
if (len == 0) {
return 0;
}
// test before we goto the native code
int test = b[off] + b[len - 1] + b[off + len - 1];
write(handle, b, off, len);
return len;
};
/**
* Write the given stream fully into this one.
*
* @param in stream write from
* @return number of bytes written from the stream
* @exception IOException if an I/O error occurs
*/
public int writeStream(InputStream in) throws IOException {
byte[] temp = new byte[1024];
int bytesRead;
int totalBytesWritten = 0;
for (;;) {
bytesRead = in.read(temp);
if (bytesRead == -1) {
return totalBytesWritten;
}
writeBytes(temp, 0, bytesRead);
totalBytesWritten += bytesRead;
}
}
/**
* Set the absolute postion of this stream.
* <p>
* Do not use this method if either <code>openInputStream</code> or
* <code>openOutputStream</code> has been called
* since the streams may be buffering data.
*
* @param absolutePosition position from the byte 0 of this stream
* @exception IOException if an I/O error occurs
*/
public void setPosition(int absolutePosition) throws IOException {
position(handle, absolutePosition);
}
/**
* Get the size of this stream.
*
* @return size of this stream in bytes
* @exception IOException if an I/O error occurs
*/
public int getSizeOf() throws IOException {
return sizeOf(handle);
}
/**
* Truncate the size of the stream to <code>size</code> bytes.
* This method cannot be used to make the size of the
* underlying stream larger.
*
* @param size new size of this stream in bytes
*
* @exception IOException if an I/O error occurs or
* <code>size</code> is larger than the stream size.
*/
public void truncate(int size) throws IOException {
truncateStream(handle, size);
}
/* NOTE: open() needs to be non-static so we can use the 'this'
* pointer to register the cleanup routine. When we have full
* native finalization, open() can be made 'static' again.
*/
/**
* Open a stream to a native file.
*
* @param szFilename filename as an 8 bit zero terminated string.
* @param mode {@link javax.microedition.io.Connection} READ, WRITE,
* or READ_WRITE
*
* @return handle to a native stream
*
* @exception IOException if an I/O error occurs
*/
private native int open(byte[] szFilename, int mode) throws IOException;
/**
* Close a native stream.
*
* @param handle native stream handle
*
* @exception IOException if an I/O error occurs
*/
private static native void close(int handle) throws IOException;
/**
* Read at least one byte from a native stream.
*
* @param handle native stream handle
* @param buffer where to put the bytes
* @param offset where in the buffer to starting putting bytes
* @param length how many bytes to read
*
* @return number of bytes read of -1 for the end of stream
*
* @exception IOException if an I/O error occurs
*/
private static native int read(int handle, byte[] buffer, int offset,
int length) throws IOException;
/**
* Write bytes to a native stream.
*
* @param handle native stream handle
* @param buffer what bytes write
* @param offset where in the buffer the bytes start
* @param length how many bytes to write
*
* @exception IOException if an I/O error occurs
*/
private static native void write(int handle, byte[] buffer, int offset,
int length) throws IOException;
/**
* Set the current position of a native stream.
*
* @param handle native stream handle
* @param absolutePosition desired position from the beginning of the
* stream.
*
* @exception IOException if an I/O error occurs
*/
private static native void position(int handle, int absolutePosition)
throws IOException;
/**
* Get the total size of a native stream.
*
* @param handle native stream handle
*
* @return size of the stream in bytes
*
* @exception IOException if an I/O error occurs
*/
private static native int sizeOf(int handle) throws IOException;
/**
* Set the size of a native stream.
*
* @param handle native stream handle
* @param size size to truncate the native stream to.
*
* @exception IOException if an I/O error occurs
*/
private static native void truncateStream(int handle, int size)
throws IOException;
/**
* Ensures native resources are freed when Object is collected.
*/
private native void finalize();
}
|