View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.provider.ram;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.DataInputStream;
21  import java.io.DataOutputStream;
22  import java.io.EOFException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.nio.charset.Charset;
26  
27  import org.apache.commons.vfs2.RandomAccessContent;
28  import org.apache.commons.vfs2.util.RandomAccessMode;
29  
30  /**
31   * RAM File Random Access Content.
32   */
33  public class RamFileRandomAccessContent implements RandomAccessContent {
34  
35      /**
36       * File Pointer
37       */
38      protected int filePointer;
39  
40      /**
41       * Buffer
42       */
43      private byte[] buf;
44  
45      /**
46       * buffer
47       */
48      private final byte[] buffer8 = new byte[8];
49  
50      /**
51       * buffer
52       */
53      private final byte[] buffer4 = new byte[4];
54  
55      /**
56       * buffer
57       */
58      private final byte[] buffer2 = new byte[2];
59  
60      /**
61       * buffer
62       */
63      private final byte[] buffer1 = new byte[1];
64  
65      /**
66       * File
67       */
68      private final RamFileObject file;
69  
70      private final InputStream rafis;
71  
72      private final static int BYTE_VALUE_MASK = 0xFF;
73  
74      /**
75       * @param file The file to access.
76       * @param mode The access mode.
77       */
78      public RamFileRandomAccessContent(final RamFileObject file, final RandomAccessMode mode) {
79          this.buf = file.getData().getContent();
80          this.file = file;
81  
82          rafis = new InputStream() {
83              @Override
84              public int read() throws IOException {
85                  try {
86                      return readByte() & BYTE_VALUE_MASK;
87                  } catch (final EOFException e) {
88                      return -1;
89                  }
90              }
91  
92              @Override
93              public long skip(final long n) throws IOException {
94                  seek(getFilePointer() + n);
95                  return n;
96              }
97  
98              @Override
99              public void close() throws IOException {
100             }
101 
102             @Override
103             public int read(final byte[] b) throws IOException {
104                 return read(b, 0, b.length);
105             }
106 
107             @Override
108             public int read(final byte[] b, final int off, final int len) throws IOException {
109                 int retLen = -1;
110                 final int left = getLeftBytes();
111                 if (left > 0) {
112                     retLen = Math.min(len, left);
113                     RamFileRandomAccessContent.this.readFully(b, off, retLen);
114                 }
115                 return retLen;
116             }
117 
118             @Override
119             public int available() throws IOException {
120                 return getLeftBytes();
121             }
122         };
123     }
124 
125     /*
126      * (non-Javadoc)
127      *
128      * @see org.apache.commons.vfs2.RandomAccessContent#getFilePointer()
129      */
130     @Override
131     public long getFilePointer() throws IOException {
132         return this.filePointer;
133     }
134 
135     /*
136      * (non-Javadoc)
137      *
138      * @see org.apache.commons.vfs2.RandomAccessContent#seek(long)
139      */
140     @Override
141     public void seek(final long pos) throws IOException {
142         if (pos < 0) {
143             throw new IOException("Attempt to position before the start of the file");
144         }
145         this.filePointer = (int) pos;
146     }
147 
148     /*
149      * (non-Javadoc)
150      *
151      * @see org.apache.commons.vfs2.RandomAccessContent#length()
152      */
153     @Override
154     public long length() throws IOException {
155         return buf.length;
156     }
157 
158     /*
159      * (non-Javadoc)
160      *
161      * @see org.apache.commons.vfs2.RandomAccessContent#close()
162      */
163     @Override
164     public void close() throws IOException {
165 
166     }
167 
168     /*
169      * (non-Javadoc)
170      *
171      * @see java.io.DataInput#readByte()
172      */
173     @Override
174     public byte readByte() throws IOException {
175         return (byte) this.readUnsignedByte();
176     }
177 
178     /*
179      * (non-Javadoc)
180      *
181      * @see java.io.DataInput#readChar()
182      */
183     @Override
184     public char readChar() throws IOException {
185         final int ch1 = this.readUnsignedByte();
186         final int ch2 = this.readUnsignedByte();
187         return (char) ((ch1 << 8) + (ch2 << 0));
188     }
189 
190     /*
191      * (non-Javadoc)
192      *
193      * @see java.io.DataInput#readDouble()
194      */
195     @Override
196     public double readDouble() throws IOException {
197         return Double.longBitsToDouble(this.readLong());
198     }
199 
200     /*
201      * (non-Javadoc)
202      *
203      * @see java.io.DataInput#readFloat()
204      */
205     @Override
206     public float readFloat() throws IOException {
207         return Float.intBitsToFloat(this.readInt());
208     }
209 
210     /*
211      * (non-Javadoc)
212      *
213      * @see java.io.DataInput#readInt()
214      */
215     @Override
216     public int readInt() throws IOException {
217         return (readUnsignedByte() << 24) | (readUnsignedByte() << 16) | (readUnsignedByte() << 8) | readUnsignedByte();
218     }
219 
220     /*
221      * (non-Javadoc)
222      *
223      * @see java.io.DataInput#readUnsignedByte()
224      */
225     @Override
226     public int readUnsignedByte() throws IOException {
227         if (filePointer < buf.length) {
228             return buf[filePointer++] & BYTE_VALUE_MASK;
229         }
230         throw new EOFException();
231     }
232 
233     /*
234      * (non-Javadoc)
235      *
236      * @see java.io.DataInput#readUnsignedShort()
237      */
238     @Override
239     public int readUnsignedShort() throws IOException {
240         this.readFully(buffer2);
241         return toUnsignedShort(buffer2);
242     }
243 
244     /*
245      * (non-Javadoc)
246      *
247      * @see java.io.DataInput#readLong()
248      */
249     @Override
250     public long readLong() throws IOException {
251         this.readFully(buffer8);
252         return toLong(buffer8);
253     }
254 
255     /*
256      * (non-Javadoc)
257      *
258      * @see java.io.DataInput#readShort()
259      */
260     @Override
261     public short readShort() throws IOException {
262         this.readFully(buffer2);
263         return toShort(buffer2);
264     }
265 
266     /*
267      * (non-Javadoc)
268      *
269      * @see java.io.DataInput#readBoolean()
270      */
271     @Override
272     public boolean readBoolean() throws IOException {
273         return this.readUnsignedByte() != 0;
274     }
275 
276     /*
277      * (non-Javadoc)
278      *
279      * @see java.io.DataInput#skipBytes(int)
280      */
281     @Override
282     public int skipBytes(final int n) throws IOException {
283         if (n < 0) {
284             throw new IndexOutOfBoundsException("The skip number can't be negative");
285         }
286 
287         final long newPos = filePointer + n;
288 
289         if (newPos > buf.length) {
290             throw new IndexOutOfBoundsException("Tyring to skip too much bytes");
291         }
292 
293         seek(newPos);
294 
295         return n;
296     }
297 
298     /*
299      * (non-Javadoc)
300      *
301      * @see java.io.DataInput#readFully(byte[])
302      */
303     @Override
304     public void readFully(final byte[] b) throws IOException {
305         this.readFully(b, 0, b.length);
306     }
307 
308     /*
309      * (non-Javadoc)
310      *
311      * @see java.io.DataInput#readFully(byte[], int, int)
312      */
313     @Override
314     public void readFully(final byte[] b, final int off, final int len) throws IOException {
315         if (len < 0) {
316             throw new IndexOutOfBoundsException("Length is lower than 0");
317         }
318 
319         if (len > this.getLeftBytes()) {
320             throw new IndexOutOfBoundsException(
321                     "Read length (" + len + ") is higher than buffer left bytes (" + this.getLeftBytes() + ") ");
322         }
323 
324         System.arraycopy(buf, filePointer, b, off, len);
325 
326         filePointer += len;
327     }
328 
329     private int getLeftBytes() {
330         return buf.length - filePointer;
331     }
332 
333     /*
334      * (non-Javadoc)
335      *
336      * @see java.io.DataInput#readUTF()
337      */
338     @Override
339     public String readUTF() throws IOException {
340         return DataInputStream.readUTF(this);
341     }
342 
343     /*
344      * (non-Javadoc)
345      *
346      * @see java.io.DataOutput#write(byte[], int, int)
347      */
348     @Override
349     public void write(final byte[] b, final int off, final int len) throws IOException {
350         if (this.getLeftBytes() < len) {
351             final int newSize = this.buf.length + len - this.getLeftBytes();
352             this.file.resize(newSize);
353             this.buf = this.file.getData().getContent();
354         }
355         System.arraycopy(b, off, this.buf, filePointer, len);
356         this.filePointer += len;
357     }
358 
359     /*
360      * (non-Javadoc)
361      *
362      * @see java.io.DataOutput#write(byte[])
363      */
364     @Override
365     public void write(final byte[] b) throws IOException {
366         this.write(b, 0, b.length);
367     }
368 
369     /*
370      * (non-Javadoc)
371      *
372      * @see java.io.DataOutput#writeByte(int)
373      */
374     @Override
375     public void writeByte(final int i) throws IOException {
376         this.write(i);
377     }
378 
379     /**
380      * Build a long from first 8 bytes of the array.
381      *
382      * @param b The byte[] to convert.
383      * @return A long.
384      */
385     public static long toLong(final byte[] b) {
386         return ((((long) b[7]) & BYTE_VALUE_MASK) + ((((long) b[6]) & BYTE_VALUE_MASK) << 8) + ((((long) b[5]) & BYTE_VALUE_MASK) << 16)
387                 + ((((long) b[4]) & BYTE_VALUE_MASK) << 24) + ((((long) b[3]) & BYTE_VALUE_MASK) << 32) + ((((long) b[2]) & BYTE_VALUE_MASK) << 40)
388                 + ((((long) b[1]) & BYTE_VALUE_MASK) << 48) + ((((long) b[0]) & BYTE_VALUE_MASK) << 56));
389     }
390 
391     /**
392      * Build a 8-byte array from a long. No check is performed on the array length.
393      *
394      * @param n The number to convert.
395      * @param b The array to fill.
396      * @return A byte[].
397      */
398     public static byte[] toBytes(long n, final byte[] b) {
399         b[7] = (byte) (n);
400         n >>>= 8;
401         b[6] = (byte) (n);
402         n >>>= 8;
403         b[5] = (byte) (n);
404         n >>>= 8;
405         b[4] = (byte) (n);
406         n >>>= 8;
407         b[3] = (byte) (n);
408         n >>>= 8;
409         b[2] = (byte) (n);
410         n >>>= 8;
411         b[1] = (byte) (n);
412         n >>>= 8;
413         b[0] = (byte) (n);
414         return b;
415     }
416 
417     /**
418      * Build a short from first 2 bytes of the array.
419      *
420      * @param b The byte[] to convert.
421      * @return A short.
422      */
423     public static short toShort(final byte[] b) {
424         return (short) toUnsignedShort(b);
425     }
426 
427     /**
428      * Build a short from first 2 bytes of the array.
429      *
430      * @param b The byte[] to convert.
431      * @return A short.
432      */
433     public static int toUnsignedShort(final byte[] b) {
434         return ((b[1] & BYTE_VALUE_MASK) + ((b[0] & BYTE_VALUE_MASK) << 8));
435     }
436 
437     /*
438      * (non-Javadoc)
439      *
440      * @see java.io.DataOutput#write(int)
441      */
442     @Override
443     public void write(final int b) throws IOException {
444         buffer1[0] = (byte) b;
445         this.write(buffer1);
446     }
447 
448     /*
449      * (non-Javadoc)
450      *
451      * @see java.io.DataOutput#writeBoolean(boolean)
452      */
453     @Override
454     public void writeBoolean(final boolean v) throws IOException {
455         this.write(v ? 1 : 0);
456     }
457 
458     /*
459      * (non-Javadoc)
460      *
461      * @see java.io.DataOutput#writeBytes(java.lang.String)
462      */
463     @Override
464     public void writeBytes(final String s) throws IOException {
465         write(s.getBytes(Charset.defaultCharset()));
466     }
467 
468     /*
469      * (non-Javadoc)
470      *
471      * @see java.io.DataOutput#writeChar(int)
472      */
473     @Override
474     public void writeChar(final int v) throws IOException {
475         buffer2[0] = (byte) ((v >>> 8) & BYTE_VALUE_MASK);
476         buffer2[1] = (byte) ((v >>> 0) & BYTE_VALUE_MASK);
477         write(buffer2);
478     }
479 
480     /*
481      * (non-Javadoc)
482      *
483      * @see java.io.DataOutput#writeChars(java.lang.String)
484      */
485     @Override
486     public void writeChars(final String s) throws IOException {
487         final int len = s.length();
488         for (int i = 0; i < len; i++) {
489             writeChar(s.charAt(i));
490         }
491     }
492 
493     /*
494      * (non-Javadoc)
495      *
496      * @see java.io.DataOutput#writeDouble(double)
497      */
498     @Override
499     public void writeDouble(final double v) throws IOException {
500         writeLong(Double.doubleToLongBits(v));
501     }
502 
503     /*
504      * (non-Javadoc)
505      *
506      * @see java.io.DataOutput#writeFloat(float)
507      */
508     @Override
509     public void writeFloat(final float v) throws IOException {
510         writeInt(Float.floatToIntBits(v));
511     }
512 
513     /*
514      * (non-Javadoc)
515      *
516      * @see java.io.DataOutput#writeInt(int)
517      */
518     @Override
519     public void writeInt(final int v) throws IOException {
520         buffer4[0] = (byte) ((v >>> 24) & BYTE_VALUE_MASK);
521         buffer4[1] = (byte) ((v >>> 16) & BYTE_VALUE_MASK);
522         buffer4[2] = (byte) ((v >>> 8) & BYTE_VALUE_MASK);
523         buffer4[3] = (byte) (v & BYTE_VALUE_MASK);
524         write(buffer4);
525     }
526 
527     /*
528      * (non-Javadoc)
529      *
530      * @see java.io.DataOutput#writeLong(long)
531      */
532     @Override
533     public void writeLong(final long v) throws IOException {
534         write(toBytes(v, buffer8));
535     }
536 
537     /*
538      * (non-Javadoc)
539      *
540      * @see java.io.DataOutput#writeShort(int)
541      */
542     @Override
543     public void writeShort(final int v) throws IOException {
544         buffer2[0] = (byte) ((v >>> 8) & BYTE_VALUE_MASK);
545         buffer2[1] = (byte) (v & BYTE_VALUE_MASK);
546         write(buffer2);
547     }
548 
549     /*
550      * (non-Javadoc)
551      *
552      * @see java.io.DataOutput#writeUTF(java.lang.String)
553      */
554     @Override
555     public void writeUTF(final String str) throws IOException {
556         final ByteArrayOutputStream out = new ByteArrayOutputStream(str.length());
557         final DataOutputStream dataOut = new DataOutputStream(out);
558         dataOut.writeUTF(str);
559         dataOut.flush();
560         dataOut.close();
561         final byte[] b = out.toByteArray();
562         write(b);
563     }
564 
565     /*
566      * (non-Javadoc)
567      *
568      * @see java.io.DataInput#readLine()
569      */
570     @Override
571     public String readLine() throws IOException {
572         throw new UnsupportedOperationException("deprecated");
573     }
574 
575     @Override
576     public InputStream getInputStream() throws IOException {
577         return rafis;
578     }
579 
580     @Override
581     public void setLength(final long newLength) throws IOException {
582         this.file.resize(newLength);
583         this.buf = this.file.getData().getContent();
584     }
585 }