| /* |
| * 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(); |
| } |
| } |