/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package java.io;
import com.google.gwt.corp.localstorage.LocalStorage;
/**
* Saves binary data to the local storage; currently using hex encoding.
* The string is prefixed with "hex:"
* @author haustein
*/
public class RandomAccessFile /*implements DataOutput, DataInput, Closeable*/ {
/*
public final FileDescriptor getFD() throws IOException { }
public final FileChannel getChannel() { }
*/
final String name;
final boolean writeable;
boolean dirty;
String data;
int newDataPos;
StringBuilder newData;
int pos;
int len;
DataInputStream dis = new DataInputStream(new RafInputStream());
DataOutputStream dos = new DataOutputStream(new RafOutputStream());
public RandomAccessFile(String name, String mode) throws FileNotFoundException {
this (new File(name), mode);
}
public RandomAccessFile(File file, String mode) throws FileNotFoundException {
name = file.getCanonicalPath();
mode = mode.toLowerCase();
if (!mode.equals("r") && !mode.equals("rw")) {
throw new IllegalArgumentException("mode: '" + mode + "'");
}
writeable = mode.equals("rw");
if (file.exists()) {
try {
data = atob(LocalStorage.getItem(name));
len = data.length();
} catch (IOException e) {
throw new FileNotFoundException("" + e);
}
} else if (writeable) {
data = "";
dirty = true;
try {
flush();
} catch (IOException e) {
throw new FileNotFoundException("" + e);
}
} else {
throw new FileNotFoundException(name);
}
}
static native String btoa(String s) /*-{
return $wnd.btoa(s);
}-*/;
static native String atob(String s) /*-{
return $wnd.atob(s);
}-*/;
public int read() throws IOException {
return dis.read();
}
public int read(byte b[], int off, int len) throws IOException {
return dis.read(b, off, len);
}
public int read(byte b[]) throws IOException {
return dis.read(b);
}
public final void readFully(byte b[]) throws IOException {
dis.readFully(b);
}
public final void readFully(byte b[], int off, int len) throws IOException {
dis.readFully(b, off, len);
}
public int skipBytes(int n) throws IOException {
return dis.skipBytes(n);
}
public void write(int b) throws IOException {
dos.write(b);
};
public void write(byte b[]) throws IOException {
dos.write(b);
}
public void write(byte b[], int off, int len) throws IOException {
dos.write(b, off, len);
}
public long getFilePointer() throws IOException {
return pos;
}
public void seek(long pos) throws IOException {
if (pos < 0) {
throw new IllegalArgumentException();
}
this.pos = (int) pos;
}
public long length() throws IOException {
return len;
}
public void setLength(long newLength) throws IOException {
if (len != newLength) {
consolidate();
if (data.length() > newLength) {
data = data.substring(0, (int) newLength);
len = (int) newLength;
} else {
// System.out.println("padding " + (newLength - len) + " zeros in setLength to " + newLength);
while (len < newLength) {
write(0);
}
}
}
}
public void close() throws IOException {
if (data != null) {
flush();
data = null;
}
}
private void consolidate() {
if (newData == null) {
return;
}
// System.out.println("consolidate(); ndp: " + newDataPos + " nd-len: " + newData.length());
if (data.length() < newDataPos) {
StringBuilder filler = new StringBuilder();
while (data.length() + filler.length() < newDataPos) {
filler.append('\0');
}
// System.out.println("padding " + (filler.length()) + " zeros in consolidate ");
data += filler.toString();
}
int p2 = newDataPos + newData.length();
data = data.substring(0, newDataPos) + newData.toString() +
(p2 < data.length() ? data.substring(p2) : "");
newData = null;
}
void flush() throws IOException {
if (!dirty) {
return;
}
consolidate();
LocalStorage.setItem(name, btoa(data));
dirty = false;
}
public final boolean readBoolean() throws IOException {
return dis.readBoolean();
}
public final byte readByte() throws IOException {
return dis.readByte();
}
public final int readUnsignedByte() throws IOException {
return dis.readUnsignedByte();
}
public final short readShort() throws IOException {
return dis.readShort();
}
public final int readUnsignedShort() throws IOException {
return dis.readUnsignedShort();
}
public final char readChar() throws IOException {
return dis.readChar();
}
public final int readInt() throws IOException {
return dis.readInt();
}
public final long readLong() throws IOException {
return dis.readLong();
}
public final float readFloat() throws IOException {
return dis.readFloat();
}
public final double readDouble() throws IOException {
return dis.readDouble();
}
public final String readLine() throws IOException {
return dis.readLine();
}
public final String readUTF() throws IOException {
return dis.readUTF();
}
public final void writeBoolean(boolean v) throws IOException {
dos.writeBoolean(v);
}
public final void writeByte(int v) throws IOException {
dos.writeByte(v);
}
public final void writeShort(int v) throws IOException {
dos.writeShort(v);
}
public final void writeChar(int v) throws IOException {
dos.writeChar(v);
}
public final void writeInt(int v) throws IOException {
dos.writeInt(v);
}
public final void writeLong(long v) throws IOException {
dos.writeLong(v);
}
public final void writeFloat(float v) throws IOException {
dos.writeFloat(v);
}
public final void writeDouble(double v) throws IOException {
dos.writeDouble(v);
}
public final void writeBytes(String s) throws IOException {
dos.writeBytes(s);
}
public final void writeChars(String s) throws IOException {
dos.writeChars(s);
}
public final void writeUTF(String str) throws IOException {
dos.writeUTF(str);
}
// public final FileChannel getChannel() throws IOException { }
class RafInputStream extends InputStream {
@Override
public int read() throws IOException {
if (pos >= len) {
return -1;
} else {
consolidate();
return data.charAt(pos++);
// int p2 = (pos << 1);
// int result = Character.digit(data.charAt(p2), 16) * 16 +
// Character.digit(data.charAt(p2 + 1), 16);
// pos++;
// return result;
}
}
}
class RafOutputStream extends OutputStream {
public void write(int b) throws IOException {
if (!writeable) {
throw new IOException("not writeable");
}
if (newData == null) {
newDataPos = pos;
newData = new StringBuilder();
// System.out.println("no buf; newDataPos: " + pos);
} else if (newDataPos + newData.length() != pos) {
consolidate();
newDataPos = pos;
newData = new StringBuilder();
// System.out.println("pos mismatch; newDataPos: " + pos);
}
newData.append((char) (b&255));
// newData.append("" + Character.forDigit((b >> 4) & 15, 16) +
// Character.forDigit(b & 15, 16));
pos++;
len = Math.max(pos, len);
dirty = true;
}
}
}