1/*
2 * $Id: RandomAccessFileOrArray.java,v 1.48 2005/09/11 08:38:18 blowagie Exp $
3 * $Name: $
4 *
5 * Copyright 2001, 2002 Paulo Soares
6 *
7 *
8 * The Original Code is 'iText, a free JAVA-PDF library'.
9 *
10 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
11 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
12 * All Rights Reserved.
13 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
14 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
15 * Co-Developer of the code is Sid Steward. Portions created by the Co-Developer
16 * are Copyright (C) 2013 by Sid Steward. All Rights Reserved.
17 *
18 * Contributor(s): all the names of the contributors are added in the source code
19 * where applicable.
20 *
21 *
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Library General Public
24 * License as published by the Free Software Foundation; either
25 * version 2 of the License, or (at your option) any later version.
26 *
27 * This library is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 * Library General Public License for more details.
31 *
32 * You should have received a copy of the GNU Library General Public
33 * License along with this library; if not, write to the
34 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
35 * Boston, MA 02110-1301, USA.
36 *
37 *
38 * This library is free software; you can redistribute it and/or
39 * modify it under the terms of the GNU Library General Public
40 * License as published by the Free Software Foundation; either
41 * version 2 of the License, or (at your option) any later version.
42 *
43 * This library is distributed in the hope that it will be useful,
44 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
46 * Library General Public License for more details.
47 *
48 * You should have received a copy of the GNU Library General Public
49 * License along with this library; if not, write to the
50 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
51 * Boston, MA 02110-1301, USA.
52 *
53 *
54 * If you didn't download this code from the following link, you should check if
55 * you aren't using an obsolete version:
56 * http://www.lowagie.com/iText/
57 */
58
59package com.gitlab.pdftk_java.com.lowagie.text.pdf;
60
61import java.io.DataInputStream;
62import java.io.DataInput;
63import java.io.FileInputStream;
64import java.io.IOException;
65import java.io.EOFException;
66import java.io.RandomAccessFile;
67import java.io.File;
68import java.io.InputStream;
69import java.io.ByteArrayOutputStream;
70import java.net.URL;
71/** An implementation of a RandomAccessFile for input only
72 * that accepts a file or a byte array as data source.
73 *
74 * @author Paulo Soares (psoares@consiste.pt)
75 */
76public class RandomAccessFileOrArray implements DataInput {
77
78 ////
79 // uses either rf or arrayIn, but not both
80
81 String filename = null; // set only if we expect to use rf (not arrayIn)
82 RandomAccessFile rf = null; // may be null even if filename is set
83
84 byte arrayIn[] = null; // set only if we aren't using filename/rf
85 int arrayInPtr = 0;
86
87 private byte back = 0;
88 private boolean isBack = false;
89
90 private int startOffset = 0;
91
92 ////
93 //
94
95 //
96 public RandomAccessFileOrArray(String filename) throws IOException {
97 this(filename, false);
98 }
99
100 //
101 public RandomAccessFileOrArray(String filename, boolean forceRead) throws IOException {
102 if (filename == null)
103 throw new IllegalArgumentException
104 ("null filename passed into RandomAccessFileOrArray()");
105
106 File file = new File(filename);
107
108 if (!file.canRead()) {
109 if (filename.startsWith("file:/") || filename.startsWith("http://") ||
110 filename.startsWith("https://") || filename.startsWith("jar:"))
111 {
112 // copied from RandomAccessFileOrArray(URL):
113 InputStream is = new URL(filename).openStream();
114 try {
115 this.inputStreamToArray(is);
116 }
117 finally {
118 try { is.close(); } catch (IOException ioe) {}
119 }
120 }
121 else {
122 InputStream is = BaseFont.getResourceStream(filename);
123 if (is == null)
124 throw new IOException(filename + " not found as file or resource.");
125 try {
126 this.inputStreamToArray(is);
127 }
128 finally {
129 try { is.close(); } catch (IOException ioe) {}
130 }
131 }
132 }
133 else if (forceRead) {
134 InputStream is = null;
135 try {
136 is = new FileInputStream(file);
137 this.inputStreamToArray(is);
138 }
139 finally {
140 try { if (is != null) { is.close(); } } catch (Exception e) {}
141 }
142 }
143 else {
144 rf = new RandomAccessFile(file, "r");
145 if (rf == null)
146 throw new IOException("Unable to open: " + filename);
147
148 this.filename = filename; // set only if we're using rf
149 }
150 }
151
152 public RandomAccessFileOrArray(URL url) throws IOException {
153 if (url == null)
154 throw new IllegalArgumentException
155 ("null url passed into RandomAccessFileOrArray()");
156
157 InputStream is = url.openStream();
158 try {
159 this.inputStreamToArray(is);
160 }
161 finally {
162 try { is.close(); } catch (IOException ioe) {}
163 }
164 }
165
166 public RandomAccessFileOrArray(InputStream is) throws IOException {
167 this.inputStreamToArray(is);
168 }
169
170 public RandomAccessFileOrArray(byte arrayIn[]) {
171 this.arrayIn = arrayIn;
172 }
173
174 // copy constructor
175 public RandomAccessFileOrArray(RandomAccessFileOrArray file) throws IOException {
176 if (file == null)
177 throw new IllegalArgumentException
178 ("null file passed into RandomAccessFileOrArray() copy constructor");
179
180 if( file.filename != null ) {
181 this.filename = file.filename;
182 this.rf = null;
183 }
184 else if( file.arrayIn != null ) {
185 this.arrayIn = file.arrayIn;
186 this.arrayInPtr = 0;
187 }
188
189 this.startOffset = file.startOffset;
190 }
191
192 ////
193 //
194
195 //
196 private void inputStreamToArray(InputStream is) throws IOException {
197 byte bb[] = new byte[8192];
198 ByteArrayOutputStream out = new ByteArrayOutputStream();
199 int len = 0;
200 while ( 1< (len = is.read(bb)) ) {
201 out.write(bb, 0, len);
202 }
203 this.arrayIn = out.toByteArray(); // allocates a new byte array
204 this.arrayInPtr = 0;
205 }
206
207 // added pushBack isBack test since we hold only one byte
208 public void pushBack(byte b) throws IOException {
209 if (isBack)
210 throw new IOException("Tried to pushBack a byte when isBack is true.");
…lines 211–230 unchanged (20 lines)
231 back = 0;
232 isBack = false;
233 }
234
235 // reads one byte
236 public int read() throws IOException {
237 int retVal = -1;
238 if (isBack) {
239 retVal = getBack();
240 clearBack();
241 }
242 else if (rf != null) {
243 retVal = rf.read();
244 }
245 else if (arrayIn != null &&
246 0<= arrayInPtr && arrayInPtr< arrayIn.length) {
247 retVal = arrayIn[arrayInPtr++] & 0xff;
248 }
249 return retVal;
250 }
251
252 // bb: buffer to read into
253 // off: index of b where to begin
254 // len: max number of bytes to copy
255 // return: number of bytes read, or -1 on end
256 public int read( byte[] bb, int off, int len ) throws IOException {
257 if( bb== null )
258 throw new IllegalArgumentException("read() argument bb is null.");
259
260 if( len== 0 || bb.length== 0 )
261 return 0; // nothing read; test before (bb.length<= off)
262
263 if( len< 0 || off< 0 || bb.length<= off || bb.length< off+ len )
264 throw new IllegalArgumentException
265 ("read() arguments are out of bounds: len: "+ len+
266 " off: "+ off+ " bb.length: "+ bb.length);
267
268 int retVal= -1; // default: end of data
269
270 // test for pushed-back byte
271 if( isBack ) { // prepend byte; reset later
272 bb[ off++ ]= back;
273 --len;
274 }
275
276 if( rf!= null ) { // use rf
277 retVal= rf.read( bb, off, len ); // could return -1
278 }
279
280 else if( arrayIn!= null ) { // use array
281 if( 0<= arrayInPtr && arrayInPtr< arrayIn.length ) {
282
283 if( arrayIn.length< arrayInPtr+ len )
284 len= arrayIn.length- arrayInPtr; // take only what's left
285
286 if( 0< len ) {
287 System.arraycopy( arrayIn, arrayInPtr, bb, off, len );
288 arrayInPtr+= len;
289 retVal= len;
290 }
291 // else end of array data
292 }
293 // else end of array data
…lines 294–299 unchanged (6 lines)
300 retVal+= 1;
301 clearBack();
302
303 return retVal;
304 }
305
306 //
307 public int read(byte b[]) throws IOException {
308 return read(b, 0, b.length);
309 }
310
311 //
312 public void readFully( byte bb[], int off, int len ) throws IOException {
313 int bytesRead= 0;
314 int nn= 0;
315 while( bytesRead< len ) { // len may be 0
316 nn= this.read( bb, off+ bytesRead, len- bytesRead );
317 if( nn< 0 )
318 throw new EOFException();
319 bytesRead+= nn;
320 }
321 }
322 public void readFully( byte bb[] ) throws IOException {
323 readFully( bb, 0, bb.length );
324 }
325
326 // calls clearBack()
327 public void reOpen() throws IOException {
328 if (filename != null && rf == null) {
329 rf = new RandomAccessFile(filename, "r");
330 if (rf == null) {
331 throw new IOException("Unable to reOpen: " + filename);
332 }
333 }
334 this.seek(0); // calls clearBack()
335 }
336
337 // might call clearBack()
338 protected void insureOpen() throws IOException {
339 if (filename != null && rf == null) {
340 reOpen();
341 }
342 }
343
344 //
345 public boolean isOpen() {
346 return (filename == null || rf != null);
347 }
348
349 //
350 public void close() throws IOException {
351 if (rf != null) {
352 rf.close();
353 rf = null;
354 }
355 // preserves this.filename and this.arrayIn
356
357 clearBack();
358 }
359
360 //
361 public int length() throws IOException {
362 if (filename != null) {
363 insureOpen();
364 return (int)rf.length() - startOffset;
365 }
366 else if (arrayIn != null) {
367 return arrayIn.length - startOffset;
368 }
369 return 0;
370 }
371
372 //
373 public int getFilePointer() throws IOException {
374 insureOpen(); // might call clearBack(), so call first
375 int nn = isBack ? 1 : 0;
376 if (filename != null) {
377 return (int)rf.getFilePointer() - nn - startOffset;
378 }
379 else if (arrayIn != null) {
380 return arrayInPtr - nn - startOffset;
381 }
382 return 0; // no data -- shouldn't happen
383 }
384
385 //
386 public void seek(int pos) throws IOException {
387 pos += startOffset;
388
389 clearBack();
390
391 if (filename != null) {
392 // not calling insureOpen() b/c it calls reOpen() which calls this.seek(0)
393 if (rf == null) {
394 rf = new RandomAccessFile(filename, "r");
395 if (rf == null) {
396 throw new IOException("Unable to open: " + filename + " in seek()");
397 }
398 }
399 rf.seek(pos);
400 }
401 else if (arrayIn != null) {
402 arrayInPtr = pos;
403 }
404 }
405
406 //
407 public void seek(long pos) throws IOException {
408 seek((int)pos);
409 }
410
411 //
412 public int skipBytes(int nn) throws IOException {
413 if (nn <= 0) {
414 return 0;
415 }
416 if (nn == 1 && isBack) {
417 clearBack();
418 return 1;
419 }
420 // no need for additional isBack logic b/c helper functions already consider it
421
422 int pos = this.getFilePointer(); // considers isBack and startOffset
423 int len = this.length(); // considers startOffset
424 int newpos = pos + nn;
425 if (newpos > len) {
426 newpos = len; // seek(len) ensures that next read() returns -1
427 }
428 this.seek(newpos); // considers startOffset
429
430 return newpos - pos;
431 }
432
433 //
434 public long skip(long n) throws IOException {
435 return skipBytes((int)n);
436 }
437
438 //
439 public int getStartOffset() {
440 return this.startOffset;
441 }
442 public void setStartOffset(int startOffset) throws IOException {
443 this.startOffset = startOffset;
444 this.seek(0);
445 }
446
447 ////
448 //
449
450 public boolean readBoolean() throws IOException {
451 int ch = this.read();
452 if (ch < 0)
453 throw new EOFException();
454 return (ch != 0);
…lines 455–714 unchanged (260 lines)
715 return input.toString();
716 }
717
718 public String readUTF() throws IOException {
719 return DataInputStream.readUTF(this);
720 }
721
722}
723