blob: 26c4b9d4f4434fc86226971ed4dbacc1f7c40b24 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.vfs2.provider.ram;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.vfs2.RandomAccessContent;
import org.apache.commons.vfs2.util.RandomAccessMode;
/**
* RAM File Random Access Content.
*/
public class RamFileRandomAccessContent implements RandomAccessContent {
/**
* File Pointer
*/
protected int filePointer = 0;
/**
* Buffer
*/
private byte[] buf;
/**
* buffer
*/
private final byte[] buffer8 = new byte[8];
/**
* buffer
*/
private final byte[] buffer4 = new byte[4];
/**
* buffer
*/
private final byte[] buffer2 = new byte[2];
/**
* buffer
*/
private final byte[] buffer1 = new byte[1];
/**
* File
*/
private final RamFileObject file;
private final InputStream rafis;
private final static int BYTE_VALUE_MASK = 0xFF;
/**
* @param file The file to access.
* @param mode The access mode.
*/
public RamFileRandomAccessContent(final RamFileObject file, final RandomAccessMode mode) {
this.buf = file.getData().getContent();
this.file = file;
rafis = new InputStream() {
@Override
public int read() throws IOException {
try {
return readByte() & BYTE_VALUE_MASK;
} catch (final EOFException e) {
return -1;
}
}
@Override
public long skip(final long n) throws IOException {
seek(getFilePointer() + n);
return n;
}
@Override
public void close() throws IOException {
}
@Override
public int read(final byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
int retLen = -1;
final int left = getLeftBytes();
if (left > 0) {
retLen = Math.min(len, left);
RamFileRandomAccessContent.this.readFully(b, off, retLen);
}
return retLen;
}
@Override
public int available() throws IOException {
return getLeftBytes();
}
};
}
/*
* (non-Javadoc)
*
* @see org.apache.commons.vfs2.RandomAccessContent#getFilePointer()
*/
@Override
public long getFilePointer() throws IOException {
return this.filePointer;
}
/*
* (non-Javadoc)
*
* @see org.apache.commons.vfs2.RandomAccessContent#seek(long)
*/
@Override
public void seek(final long pos) throws IOException {
if (pos < 0) {
throw new IOException("Attempt to position before the start of the file");
}
this.filePointer = (int) pos;
}
/*
* (non-Javadoc)
*
* @see org.apache.commons.vfs2.RandomAccessContent#length()
*/
@Override
public long length() throws IOException {
return buf.length;
}
/*
* (non-Javadoc)
*
* @see org.apache.commons.vfs2.RandomAccessContent#close()
*/
@Override
public void close() throws IOException {
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readByte()
*/
@Override
public byte readByte() throws IOException {
return (byte) this.readUnsignedByte();
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readChar()
*/
@Override
public char readChar() throws IOException {
final int ch1 = this.readUnsignedByte();
final int ch2 = this.readUnsignedByte();
return (char) ((ch1 << 8) + (ch2 << 0));
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readDouble()
*/
@Override
public double readDouble() throws IOException {
return Double.longBitsToDouble(this.readLong());
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readFloat()
*/
@Override
public float readFloat() throws IOException {
return Float.intBitsToFloat(this.readInt());
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readInt()
*/
@Override
public int readInt() throws IOException {
return (readUnsignedByte() << 24) | (readUnsignedByte() << 16) | (readUnsignedByte() << 8) | readUnsignedByte();
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readUnsignedByte()
*/
@Override
public int readUnsignedByte() throws IOException {
if (filePointer < buf.length) {
return buf[filePointer++] & BYTE_VALUE_MASK;
}
throw new EOFException();
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readUnsignedShort()
*/
@Override
public int readUnsignedShort() throws IOException {
this.readFully(buffer2);
return toUnsignedShort(buffer2);
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readLong()
*/
@Override
public long readLong() throws IOException {
this.readFully(buffer8);
return toLong(buffer8);
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readShort()
*/
@Override
public short readShort() throws IOException {
this.readFully(buffer2);
return toShort(buffer2);
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readBoolean()
*/
@Override
public boolean readBoolean() throws IOException {
return this.readUnsignedByte() != 0;
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#skipBytes(int)
*/
@Override
public int skipBytes(final int n) throws IOException {
if (n < 0) {
throw new IndexOutOfBoundsException("The skip number can't be negative");
}
final long newPos = filePointer + n;
if (newPos > buf.length) {
throw new IndexOutOfBoundsException("Tyring to skip too much bytes");
}
seek(newPos);
return n;
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readFully(byte[])
*/
@Override
public void readFully(final byte[] b) throws IOException {
this.readFully(b, 0, b.length);
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readFully(byte[], int, int)
*/
@Override
public void readFully(final byte[] b, final int off, final int len) throws IOException {
if (len < 0) {
throw new IndexOutOfBoundsException("Length is lower than 0");
}
if (len > this.getLeftBytes()) {
throw new IndexOutOfBoundsException(
"Read length (" + len + ") is higher than buffer left bytes (" + this.getLeftBytes() + ") ");
}
System.arraycopy(buf, filePointer, b, off, len);
filePointer += len;
}
private int getLeftBytes() {
return buf.length - filePointer;
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readUTF()
*/
@Override
public String readUTF() throws IOException {
return DataInputStream.readUTF(this);
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#write(byte[], int, int)
*/
@Override
public void write(final byte[] b, final int off, final int len) throws IOException {
if (this.getLeftBytes() < len) {
final int newSize = this.buf.length + len - this.getLeftBytes();
this.file.resize(newSize);
this.buf = this.file.getData().getContent();
}
System.arraycopy(b, off, this.buf, filePointer, len);
this.filePointer += len;
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#write(byte[])
*/
@Override
public void write(final byte[] b) throws IOException {
this.write(b, 0, b.length);
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeByte(int)
*/
@Override
public void writeByte(final int i) throws IOException {
this.write(i);
}
/**
* Build a long from first 8 bytes of the array.
*
* @param b The byte[] to convert.
* @return A long.
*/
public static long toLong(final byte[] b) {
return ((((long) b[7]) & BYTE_VALUE_MASK) + ((((long) b[6]) & BYTE_VALUE_MASK) << 8) + ((((long) b[5]) & BYTE_VALUE_MASK) << 16)
+ ((((long) b[4]) & BYTE_VALUE_MASK) << 24) + ((((long) b[3]) & BYTE_VALUE_MASK) << 32) + ((((long) b[2]) & BYTE_VALUE_MASK) << 40)
+ ((((long) b[1]) & BYTE_VALUE_MASK) << 48) + ((((long) b[0]) & BYTE_VALUE_MASK) << 56));
}
/**
* Build a 8-byte array from a long. No check is performed on the array length.
*
* @param n The number to convert.
* @param b The array to fill.
* @return A byte[].
*/
public static byte[] toBytes(long n, final byte[] b) {
b[7] = (byte) (n);
n >>>= 8;
b[6] = (byte) (n);
n >>>= 8;
b[5] = (byte) (n);
n >>>= 8;
b[4] = (byte) (n);
n >>>= 8;
b[3] = (byte) (n);
n >>>= 8;
b[2] = (byte) (n);
n >>>= 8;
b[1] = (byte) (n);
n >>>= 8;
b[0] = (byte) (n);
return b;
}
/**
* Build a short from first 2 bytes of the array.
*
* @param b The byte[] to convert.
* @return A short.
*/
public static short toShort(final byte[] b) {
return (short) toUnsignedShort(b);
}
/**
* Build a short from first 2 bytes of the array.
*
* @param b The byte[] to convert.
* @return A short.
*/
public static int toUnsignedShort(final byte[] b) {
return ((b[1] & BYTE_VALUE_MASK) + ((b[0] & BYTE_VALUE_MASK) << 8));
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#write(int)
*/
@Override
public void write(final int b) throws IOException {
buffer1[0] = (byte) b;
this.write(buffer1);
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeBoolean(boolean)
*/
@Override
public void writeBoolean(final boolean v) throws IOException {
this.write(v ? 1 : 0);
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeBytes(java.lang.String)
*/
@Override
public void writeBytes(final String s) throws IOException {
write(s.getBytes());
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeChar(int)
*/
@Override
public void writeChar(final int v) throws IOException {
buffer2[0] = (byte) ((v >>> 8) & BYTE_VALUE_MASK);
buffer2[1] = (byte) ((v >>> 0) & BYTE_VALUE_MASK);
write(buffer2);
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeChars(java.lang.String)
*/
@Override
public void writeChars(final String s) throws IOException {
final int len = s.length();
for (int i = 0; i < len; i++) {
writeChar(s.charAt(i));
}
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeDouble(double)
*/
@Override
public void writeDouble(final double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeFloat(float)
*/
@Override
public void writeFloat(final float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeInt(int)
*/
@Override
public void writeInt(final int v) throws IOException {
buffer4[0] = (byte) ((v >>> 24) & BYTE_VALUE_MASK);
buffer4[1] = (byte) ((v >>> 16) & BYTE_VALUE_MASK);
buffer4[2] = (byte) ((v >>> 8) & BYTE_VALUE_MASK);
buffer4[3] = (byte) (v & BYTE_VALUE_MASK);
write(buffer4);
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeLong(long)
*/
@Override
public void writeLong(final long v) throws IOException {
write(toBytes(v, buffer8));
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeShort(int)
*/
@Override
public void writeShort(final int v) throws IOException {
buffer2[0] = (byte) ((v >>> 8) & BYTE_VALUE_MASK);
buffer2[1] = (byte) (v & BYTE_VALUE_MASK);
write(buffer2);
}
/*
* (non-Javadoc)
*
* @see java.io.DataOutput#writeUTF(java.lang.String)
*/
@Override
public void writeUTF(final String str) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream(str.length());
final DataOutputStream dataOut = new DataOutputStream(out);
dataOut.writeUTF(str);
dataOut.flush();
dataOut.close();
final byte[] b = out.toByteArray();
write(b);
}
/*
* (non-Javadoc)
*
* @see java.io.DataInput#readLine()
*/
@Override
public String readLine() throws IOException {
throw new UnsupportedOperationException("deprecated");
}
@Override
public InputStream getInputStream() throws IOException {
return rafis;
}
@Override
public void setLength(final long newLength) throws IOException {
this.file.resize(newLength);
this.buf = this.file.getData().getContent();
}
}