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