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