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