2
* $Id: RandomAccessFileOrArray.java 3488 2008-06-02 14:19:26Z blowagie $
4
* Copyright 2001, 2002 Paulo Soares
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* (the "License"); you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the License.
14
* The Original Code is 'iText, a free JAVA-PDF library'.
16
* The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17
* the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
18
* All Rights Reserved.
19
* Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20
* are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
22
* Contributor(s): all the names of the contributors are added in the source code
25
* Alternatively, the contents of this file may be used under the terms of the
26
* LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27
* provisions of LGPL are applicable instead of those above. If you wish to
28
* allow use of your version of this file only under the terms of the LGPL
29
* License and not to allow others to use your version of this file under
30
* the MPL, indicate your decision by deleting the provisions above and
31
* replace them with the notice and other provisions required by the LGPL.
32
* If you do not delete the provisions above, a recipient may use your version
33
* of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
35
* This library is free software; you can redistribute it and/or modify it
36
* under the terms of the MPL as stated above or under the terms of the GNU
37
* Library General Public License as published by the Free Software Foundation;
38
* either version 2 of the License, or any later version.
40
* This library is distributed in the hope that it will be useful, but WITHOUT
41
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42
* FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
45
* If you didn't download this code from the following link, you should check if
46
* you aren't using an obsolete version:
47
* http://www.lowagie.com/iText/
50
package com.lowagie.text.pdf;
52
import com.lowagie.text.Document;
53
import java.io.ByteArrayOutputStream;
54
import java.io.DataInput;
55
import java.io.DataInputStream;
56
import java.io.EOFException;
58
import java.io.FileInputStream;
59
import java.io.IOException;
60
import java.io.InputStream;
61
import java.io.RandomAccessFile;
63
import java.nio.channels.FileChannel;
64
/** An implementation of a RandomAccessFile for input only
65
* that accepts a file or a byte array as data source.
67
* @author Paulo Soares (psoares@consiste.pt)
69
public class RandomAccessFileOrArray implements DataInput {
71
MappedRandomAccessFile rf;
73
boolean plainRandomAccess;
78
boolean isBack = false;
80
/** Holds value of property startOffset. */
81
private int startOffset = 0;
83
public RandomAccessFileOrArray(String filename) throws IOException {
84
this(filename, false, Document.plainRandomAccess);
87
public RandomAccessFileOrArray(String filename, boolean forceRead, boolean plainRandomAccess) throws IOException {
88
this.plainRandomAccess = plainRandomAccess;
89
File file = new File(filename);
90
if (!file.canRead()) {
91
if (filename.startsWith("file:/") || filename.startsWith("http://") || filename.startsWith("https://") || filename.startsWith("jar:")) {
92
InputStream is = new URL(filename).openStream();
94
this.arrayIn = InputStreamToArray(is);
98
try {is.close();}catch(IOException ioe){}
102
InputStream is = BaseFont.getResourceStream(filename);
104
throw new IOException(filename + " not found as file or resource.");
106
this.arrayIn = InputStreamToArray(is);
110
try {is.close();}catch(IOException ioe){}
114
else if (forceRead) {
115
InputStream s = null;
117
s = new FileInputStream(file);
118
this.arrayIn = InputStreamToArray(s);
121
try {if (s != null) {s.close();}}catch(Exception e){}
125
this.filename = filename;
126
if (plainRandomAccess)
127
trf = new RandomAccessFile(filename, "r");
129
rf = new MappedRandomAccessFile(filename, "r");
132
public RandomAccessFileOrArray(URL url) throws IOException {
133
InputStream is = url.openStream();
135
this.arrayIn = InputStreamToArray(is);
138
try {is.close();}catch(IOException ioe){}
142
public RandomAccessFileOrArray(InputStream is) throws IOException {
143
this.arrayIn = InputStreamToArray(is);
146
public static byte[] InputStreamToArray(InputStream is) throws IOException {
147
byte b[] = new byte[8192];
148
ByteArrayOutputStream out = new ByteArrayOutputStream();
150
int read = is.read(b);
153
out.write(b, 0, read);
156
return out.toByteArray();
159
public RandomAccessFileOrArray(byte arrayIn[]) {
160
this.arrayIn = arrayIn;
163
public RandomAccessFileOrArray(RandomAccessFileOrArray file) {
164
filename = file.filename;
165
arrayIn = file.arrayIn;
166
startOffset = file.startOffset;
167
plainRandomAccess = file.plainRandomAccess;
170
public void pushBack(byte b) {
175
public int read() throws IOException {
181
return plainRandomAccess ? trf.read() : rf.read();
183
if (arrayInPtr >= arrayIn.length)
185
return arrayIn[arrayInPtr++] & 0xff;
189
public int read(byte[] b, int off, int len) throws IOException {
205
if (arrayIn == null) {
206
return (plainRandomAccess ? trf.read(b, off, len) : rf.read(b, off, len)) + n;
209
if (arrayInPtr >= arrayIn.length)
211
if (arrayInPtr + len > arrayIn.length)
212
len = arrayIn.length - arrayInPtr;
213
System.arraycopy(arrayIn, arrayInPtr, b, off, len);
219
public int read(byte b[]) throws IOException {
220
return read(b, 0, b.length);
223
public void readFully(byte b[]) throws IOException {
224
readFully(b, 0, b.length);
227
public void readFully(byte b[], int off, int len) throws IOException {
230
int count = read(b, off + n, len - n);
232
throw new EOFException();
237
public long skip(long n) throws IOException {
238
return skipBytes((int)n);
241
public int skipBytes(int n) throws IOException {
260
pos = getFilePointer();
268
/* return the actual number of bytes skipped */
269
return newpos - pos + adj;
272
public void reOpen() throws IOException {
273
if (filename != null && rf == null && trf == null) {
274
if (plainRandomAccess)
275
trf = new RandomAccessFile(filename, "r");
277
rf = new MappedRandomAccessFile(filename, "r");
282
protected void insureOpen() throws IOException {
283
if (filename != null && rf == null && trf == null) {
288
public boolean isOpen() {
289
return (filename == null || rf != null || trf != null);
292
public void close() throws IOException {
297
// it's very expensive to open a memory mapped file and for the usage pattern of this class
298
// in iText it's faster the next re-openings to be done as a plain random access
300
plainRandomAccess = true;
302
else if (trf != null) {
308
public int length() throws IOException {
309
if (arrayIn == null) {
311
return (int)(plainRandomAccess ? trf.length() : rf.length()) - startOffset;
314
return arrayIn.length - startOffset;
317
public void seek(int pos) throws IOException {
320
if (arrayIn == null) {
322
if (plainRandomAccess)
331
public void seek(long pos) throws IOException {
335
public int getFilePointer() throws IOException {
337
int n = isBack ? 1 : 0;
338
if (arrayIn == null) {
339
return (int)(plainRandomAccess ? trf.getFilePointer() : rf.getFilePointer()) - n - startOffset;
342
return arrayInPtr - n - startOffset;
345
public boolean readBoolean() throws IOException {
346
int ch = this.read();
348
throw new EOFException();
352
public byte readByte() throws IOException {
353
int ch = this.read();
355
throw new EOFException();
359
public int readUnsignedByte() throws IOException {
360
int ch = this.read();
362
throw new EOFException();
366
public short readShort() throws IOException {
367
int ch1 = this.read();
368
int ch2 = this.read();
370
throw new EOFException();
371
return (short)((ch1 << 8) + ch2);
375
* Reads a signed 16-bit number from this stream in little-endian order.
376
* The method reads two
377
* bytes from this stream, starting at the current stream pointer.
378
* If the two bytes read, in order, are
379
* <code>b1</code> and <code>b2</code>, where each of the two values is
380
* between <code>0</code> and <code>255</code>, inclusive, then the
381
* result is equal to:
383
* (short)((b2 << 8) | b1)
384
* </pre></blockquote>
386
* This method blocks until the two bytes are read, the end of the
387
* stream is detected, or an exception is thrown.
389
* @return the next two bytes of this stream, interpreted as a signed
391
* @exception EOFException if this stream reaches the end before reading
393
* @exception IOException if an I/O error occurs.
395
public final short readShortLE() throws IOException {
396
int ch1 = this.read();
397
int ch2 = this.read();
399
throw new EOFException();
400
return (short)((ch2 << 8) + (ch1 << 0));
403
public int readUnsignedShort() throws IOException {
404
int ch1 = this.read();
405
int ch2 = this.read();
407
throw new EOFException();
408
return (ch1 << 8) + ch2;
412
* Reads an unsigned 16-bit number from this stream in little-endian order.
414
* two bytes from the stream, starting at the current stream pointer.
415
* If the bytes read, in order, are
416
* <code>b1</code> and <code>b2</code>, where
417
* <code>0 <= b1, b2 <= 255</code>,
418
* then the result is equal to:
420
* (b2 << 8) | b1
421
* </pre></blockquote>
423
* This method blocks until the two bytes are read, the end of the
424
* stream is detected, or an exception is thrown.
426
* @return the next two bytes of this stream, interpreted as an
427
* unsigned 16-bit integer.
428
* @exception EOFException if this stream reaches the end before reading
430
* @exception IOException if an I/O error occurs.
432
public final int readUnsignedShortLE() throws IOException {
433
int ch1 = this.read();
434
int ch2 = this.read();
436
throw new EOFException();
437
return (ch2 << 8) + (ch1 << 0);
440
public char readChar() throws IOException {
441
int ch1 = this.read();
442
int ch2 = this.read();
444
throw new EOFException();
445
return (char)((ch1 << 8) + ch2);
449
* Reads a Unicode character from this stream in little-endian order.
450
* This method reads two
451
* bytes from the stream, starting at the current stream pointer.
452
* If the bytes read, in order, are
453
* <code>b1</code> and <code>b2</code>, where
454
* <code>0 <= b1, b2 <= 255</code>,
455
* then the result is equal to:
457
* (char)((b2 << 8) | b1)
458
* </pre></blockquote>
460
* This method blocks until the two bytes are read, the end of the
461
* stream is detected, or an exception is thrown.
463
* @return the next two bytes of this stream as a Unicode character.
464
* @exception EOFException if this stream reaches the end before reading
466
* @exception IOException if an I/O error occurs.
468
public final char readCharLE() throws IOException {
469
int ch1 = this.read();
470
int ch2 = this.read();
472
throw new EOFException();
473
return (char)((ch2 << 8) + (ch1 << 0));
476
public int readInt() throws IOException {
477
int ch1 = this.read();
478
int ch2 = this.read();
479
int ch3 = this.read();
480
int ch4 = this.read();
481
if ((ch1 | ch2 | ch3 | ch4) < 0)
482
throw new EOFException();
483
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
487
* Reads a signed 32-bit integer from this stream in little-endian order.
488
* This method reads 4
489
* bytes from the stream, starting at the current stream pointer.
490
* If the bytes read, in order, are <code>b1</code>,
491
* <code>b2</code>, <code>b3</code>, and <code>b4</code>, where
492
* <code>0 <= b1, b2, b3, b4 <= 255</code>,
493
* then the result is equal to:
495
* (b4 << 24) | (b3 << 16) + (b2 << 8) + b1
496
* </pre></blockquote>
498
* This method blocks until the four bytes are read, the end of the
499
* stream is detected, or an exception is thrown.
501
* @return the next four bytes of this stream, interpreted as an
503
* @exception EOFException if this stream reaches the end before reading
505
* @exception IOException if an I/O error occurs.
507
public final int readIntLE() throws IOException {
508
int ch1 = this.read();
509
int ch2 = this.read();
510
int ch3 = this.read();
511
int ch4 = this.read();
512
if ((ch1 | ch2 | ch3 | ch4) < 0)
513
throw new EOFException();
514
return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
518
* Reads an unsigned 32-bit integer from this stream. This method reads 4
519
* bytes from the stream, starting at the current stream pointer.
520
* If the bytes read, in order, are <code>b1</code>,
521
* <code>b2</code>, <code>b3</code>, and <code>b4</code>, where
522
* <code>0 <= b1, b2, b3, b4 <= 255</code>,
523
* then the result is equal to:
525
* (b1 << 24) | (b2 << 16) + (b3 << 8) + b4
526
* </pre></blockquote>
528
* This method blocks until the four bytes are read, the end of the
529
* stream is detected, or an exception is thrown.
531
* @return the next four bytes of this stream, interpreted as a
533
* @exception EOFException if this stream reaches the end before reading
535
* @exception IOException if an I/O error occurs.
537
public final long readUnsignedInt() throws IOException {
538
long ch1 = this.read();
539
long ch2 = this.read();
540
long ch3 = this.read();
541
long ch4 = this.read();
542
if ((ch1 | ch2 | ch3 | ch4) < 0)
543
throw new EOFException();
544
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
547
public final long readUnsignedIntLE() throws IOException {
548
long ch1 = this.read();
549
long ch2 = this.read();
550
long ch3 = this.read();
551
long ch4 = this.read();
552
if ((ch1 | ch2 | ch3 | ch4) < 0)
553
throw new EOFException();
554
return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
557
public long readLong() throws IOException {
558
return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
561
public final long readLongLE() throws IOException {
562
int i1 = readIntLE();
563
int i2 = readIntLE();
564
return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL);
567
public float readFloat() throws IOException {
568
return Float.intBitsToFloat(readInt());
571
public final float readFloatLE() throws IOException {
572
return Float.intBitsToFloat(readIntLE());
575
public double readDouble() throws IOException {
576
return Double.longBitsToDouble(readLong());
579
public final double readDoubleLE() throws IOException {
580
return Double.longBitsToDouble(readLongLE());
583
public String readLine() throws IOException {
584
StringBuffer input = new StringBuffer();
589
switch (c = read()) {
596
int cur = getFilePointer();
597
if ((read()) != '\n') {
602
input.append((char)c);
607
if ((c == -1) && (input.length() == 0)) {
610
return input.toString();
613
public String readUTF() throws IOException {
614
return DataInputStream.readUTF(this);
617
/** Getter for property startOffset.
618
* @return Value of property startOffset.
621
public int getStartOffset() {
622
return this.startOffset;
625
/** Setter for property startOffset.
626
* @param startOffset New value of property startOffset.
629
public void setStartOffset(int startOffset) {
630
this.startOffset = startOffset;
636
public java.nio.ByteBuffer getNioByteBuffer() throws IOException {
637
if (filename != null) {
639
if (plainRandomAccess)
640
channel = trf.getChannel();
642
channel = rf.getChannel();
643
return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
645
return java.nio.ByteBuffer.wrap(arrayIn);