using System; using System.IO; using System.Text; using System.Net; /* * $Id: RandomAccessFileOrArray.cs,v 1.9 2008/05/13 11:25:23 psoares33 Exp $ * * * Copyright 2001, 2002 Paulo Soares * * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the License. * * The Original Code is 'iText, a free JAVA-PDF library'. * * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. * All Rights Reserved. * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. * * Contributor(s): all the names of the contributors are added in the source code * where applicable. * * Alternatively, the contents of this file may be used under the terms of the * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the * provisions of LGPL are applicable instead of those above. If you wish to * allow use of your version of this file only under the terms of the LGPL * License and not to allow others to use your version of this file under * the MPL, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the LGPL. * If you do not delete the provisions above, a recipient may use your version * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. * * This library is free software; you can redistribute it and/or modify it * under the terms of the MPL as stated above or under the terms of the GNU * Library General Public License as published by the Free Software Foundation; * either version 2 of the License, or any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more * details. * * If you didn't download this code from the following link, you should check if * you aren't using an obsolete version: * http://www.lowagie.com/iText/ */ namespace iTextSharp.text.pdf { /** An implementation of a RandomAccessFile for input only * that accepts a file or a byte array as data source. * * @author Paulo Soares (psoares@consiste.pt) */ public class RandomAccessFileOrArray { internal FileStream rf; internal String filename; internal byte[] arrayIn; internal int arrayInPtr; internal byte back; internal bool isBack = false; /** Holds value of property startOffset. */ private int startOffset = 0; public RandomAccessFileOrArray(String filename) : this(filename, false) { } public RandomAccessFileOrArray(String filename, bool forceRead) { if (!File.Exists(filename)) { if (filename.StartsWith("file:/") || filename.StartsWith("http://") || filename.StartsWith("https://")) { Stream isp = WebRequest.Create(new Uri(filename)).GetResponse().GetResponseStream(); try { this.arrayIn = InputStreamToArray(isp); return; } finally { try {isp.Close();}catch{} } } else { Stream isp = BaseFont.GetResourceStream(filename); if (isp == null) throw new IOException(filename + " not found as file or resource."); try { this.arrayIn = InputStreamToArray(isp); return; } finally { try {isp.Close();}catch{} } } } else if (forceRead) { Stream s = null; try { s = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); this.arrayIn = InputStreamToArray(s); } finally { try{if (s != null) s.Close();}catch{} } return; } this.filename = filename; rf = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); } public RandomAccessFileOrArray(Uri url) { Stream isp = WebRequest.Create(url).GetResponse().GetResponseStream(); try { this.arrayIn = InputStreamToArray(isp); } finally { try {isp.Close();}catch{} } } public RandomAccessFileOrArray(Stream isp) { this.arrayIn = InputStreamToArray(isp); } public static byte[] InputStreamToArray(Stream isp) { byte[] b = new byte[8192]; MemoryStream outp = new MemoryStream(); while (true) { int read = isp.Read(b, 0, b.Length); if (read < 1) break; outp.Write(b, 0, read); } return outp.ToArray(); } public RandomAccessFileOrArray(byte[] arrayIn) { this.arrayIn = arrayIn; } public RandomAccessFileOrArray(RandomAccessFileOrArray file) { filename = file.filename; arrayIn = file.arrayIn; startOffset = file.startOffset; } public void PushBack(byte b) { back = b; isBack = true; } public int Read() { if (isBack) { isBack = false; return back & 0xff; } if (arrayIn == null) return rf.ReadByte(); else { if (arrayInPtr >= arrayIn.Length) return -1; return arrayIn[arrayInPtr++] & 0xff; } } public int Read(byte[] b, int off, int len) { if (len == 0) return 0; int n = 0; if (isBack) { isBack = false; if (len == 1) { b[off] = back; return 1; } else { n = 1; b[off++] = back; --len; } } if (arrayIn == null) { return rf.Read(b, off, len) + n; } else { if (arrayInPtr >= arrayIn.Length) return -1; if (arrayInPtr + len > arrayIn.Length) len = arrayIn.Length - arrayInPtr; Array.Copy(arrayIn, arrayInPtr, b, off, len); arrayInPtr += len; return len + n; } } public int Read(byte[] b) { return Read(b, 0, b.Length); } public void ReadFully(byte[] b) { ReadFully(b, 0, b.Length); } public void ReadFully(byte[] b, int off, int len) { if (len == 0) return; int n = 0; do { int count = Read(b, off + n, len - n); if (count <= 0) throw new EndOfStreamException(); n += count; } while (n < len); } public long Skip(long n) { return SkipBytes((int)n); } public int SkipBytes(int n) { if (n <= 0) { return 0; } int adj = 0; if (isBack) { isBack = false; if (n == 1) { return 1; } else { --n; adj = 1; } } int pos; int len; int newpos; pos = FilePointer; len = Length; newpos = pos + n; if (newpos > len) { newpos = len; } Seek(newpos); /* return the actual number of bytes skipped */ return newpos - pos + adj; } public void ReOpen() { if (filename != null && rf == null) rf = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); Seek(0); } protected void InsureOpen() { if (filename != null && rf == null) { ReOpen(); } } public bool IsOpen() { return (filename == null || rf != null); } public void Close() { isBack = false; if (rf != null) { rf.Close(); rf = null; } } public int Length { get { if (arrayIn == null) { InsureOpen(); return (int)rf.Length - startOffset; } else return arrayIn.Length - startOffset; } } public void Seek(int pos) { pos += startOffset; isBack = false; if (arrayIn == null) { InsureOpen(); rf.Position = pos; } else arrayInPtr = pos; } public void Seek(long pos) { Seek((int)pos); } public int FilePointer { get { InsureOpen(); int n = isBack ? 1 : 0; if (arrayIn == null) { return (int)rf.Position - n - startOffset; } else return arrayInPtr - n - startOffset; } } public bool ReadBoolean() { int ch = this.Read(); if (ch < 0) throw new EndOfStreamException(); return (ch != 0); } public byte ReadByte() { int ch = this.Read(); if (ch < 0) throw new EndOfStreamException(); return (byte)(ch); } public int ReadUnsignedByte() { int ch = this.Read(); if (ch < 0) throw new EndOfStreamException(); return ch; } public short ReadShort() { int ch1 = this.Read(); int ch2 = this.Read(); if ((ch1 | ch2) < 0) throw new EndOfStreamException(); return (short)((ch1 << 8) + ch2); } /** * Reads a signed 16-bit number from this stream in little-endian order. * The method reads two * bytes from this stream, starting at the current stream pointer. * If the two bytes read, in order, are * b1 and b2, where each of the two values is * between 0 and 255, inclusive, then the * result is equal to: *
        *     (short)((b2 << 8) | b1)
        * 
*

* This method blocks until the two bytes are read, the end of the * stream is detected, or an exception is thrown. * * @return the next two bytes of this stream, interpreted as a signed * 16-bit number. * @exception EOFException if this stream reaches the end before reading * two bytes. * @exception IOException if an I/O error occurs. */ public short ReadShortLE() { int ch1 = this.Read(); int ch2 = this.Read(); if ((ch1 | ch2) < 0) throw new EndOfStreamException(); return (short)((ch2 << 8) + (ch1 << 0)); } public int ReadUnsignedShort() { int ch1 = this.Read(); int ch2 = this.Read(); if ((ch1 | ch2) < 0) throw new EndOfStreamException(); return (ch1 << 8) + ch2; } /** * Reads an unsigned 16-bit number from this stream in little-endian order. * This method reads * two bytes from the stream, starting at the current stream pointer. * If the bytes read, in order, are * b1 and b2, where * 0 <= b1, b2 <= 255, * then the result is equal to: *

        *     (b2 << 8) | b1
        * 
*

* This method blocks until the two bytes are read, the end of the * stream is detected, or an exception is thrown. * * @return the next two bytes of this stream, interpreted as an * unsigned 16-bit integer. * @exception EOFException if this stream reaches the end before reading * two bytes. * @exception IOException if an I/O error occurs. */ public int ReadUnsignedShortLE() { int ch1 = this.Read(); int ch2 = this.Read(); if ((ch1 | ch2) < 0) throw new EndOfStreamException(); return (ch2 << 8) + (ch1 << 0); } public char ReadChar() { int ch1 = this.Read(); int ch2 = this.Read(); if ((ch1 | ch2) < 0) throw new EndOfStreamException(); return (char)((ch1 << 8) + ch2); } /** * Reads a Unicode character from this stream in little-endian order. * This method reads two * bytes from the stream, starting at the current stream pointer. * If the bytes read, in order, are * b1 and b2, where * 0 <= b1, b2 <= 255, * then the result is equal to: *

        *     (char)((b2 << 8) | b1)
        * 
*

* This method blocks until the two bytes are read, the end of the * stream is detected, or an exception is thrown. * * @return the next two bytes of this stream as a Unicode character. * @exception EOFException if this stream reaches the end before reading * two bytes. * @exception IOException if an I/O error occurs. */ public char ReadCharLE() { int ch1 = this.Read(); int ch2 = this.Read(); if ((ch1 | ch2) < 0) throw new EndOfStreamException(); return (char)((ch2 << 8) + (ch1 << 0)); } public int ReadInt() { int ch1 = this.Read(); int ch2 = this.Read(); int ch3 = this.Read(); int ch4 = this.Read(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EndOfStreamException(); return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); } /** * Reads a signed 32-bit integer from this stream in little-endian order. * This method reads 4 * bytes from the stream, starting at the current stream pointer. * If the bytes read, in order, are b1, * b2, b3, and b4, where * 0 <= b1, b2, b3, b4 <= 255, * then the result is equal to: *

        *     (b4 << 24) | (b3 << 16) + (b2 << 8) + b1
        * 
*

* This method blocks until the four bytes are read, the end of the * stream is detected, or an exception is thrown. * * @return the next four bytes of this stream, interpreted as an * int. * @exception EOFException if this stream reaches the end before reading * four bytes. * @exception IOException if an I/O error occurs. */ public int ReadIntLE() { int ch1 = this.Read(); int ch2 = this.Read(); int ch3 = this.Read(); int ch4 = this.Read(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EndOfStreamException(); return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); } /** * Reads an unsigned 32-bit integer from this stream. This method reads 4 * bytes from the stream, starting at the current stream pointer. * If the bytes read, in order, are b1, * b2, b3, and b4, where * 0 <= b1, b2, b3, b4 <= 255, * then the result is equal to: *

        *     (b1 << 24) | (b2 << 16) + (b3 << 8) + b4
        * 
*

* This method blocks until the four bytes are read, the end of the * stream is detected, or an exception is thrown. * * @return the next four bytes of this stream, interpreted as a * long. * @exception EOFException if this stream reaches the end before reading * four bytes. * @exception IOException if an I/O error occurs. */ public long ReadUnsignedInt() { long ch1 = this.Read(); long ch2 = this.Read(); long ch3 = this.Read(); long ch4 = this.Read(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EndOfStreamException(); return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); } public long ReadUnsignedIntLE() { long ch1 = this.Read(); long ch2 = this.Read(); long ch3 = this.Read(); long ch4 = this.Read(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EndOfStreamException(); return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); } public long ReadLong() { return ((long)(ReadInt()) << 32) + (ReadInt() & 0xFFFFFFFFL); } public long ReadLongLE() { int i1 = ReadIntLE(); int i2 = ReadIntLE(); return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL); } public float ReadFloat() { int[] a = {ReadInt()}; float[] b = {0}; Buffer.BlockCopy(a, 0, b, 0, 4); return b[0]; } public float ReadFloatLE() { int[] a = {ReadIntLE()}; float[] b = {0}; Buffer.BlockCopy(a, 0, b, 0, 4); return b[0]; } public double ReadDouble() { long[] a = {ReadLong()}; double[] b = {0}; Buffer.BlockCopy(a, 0, b, 0, 8); return b[0]; } public double ReadDoubleLE() { long[] a = {ReadLongLE()}; double[] b = {0}; Buffer.BlockCopy(a, 0, b, 0, 8); return b[0]; } public String ReadLine() { StringBuilder input = new StringBuilder(); int c = -1; bool eol = false; while (!eol) { switch (c = Read()) { case -1: case '\n': eol = true; break; case '\r': eol = true; int cur = FilePointer; if ((Read()) != '\n') { Seek(cur); } break; default: input.Append((char)c); break; } } if ((c == -1) && (input.Length == 0)) { return null; } return input.ToString(); } public int StartOffset { get { return startOffset; } set { startOffset = value; } } } }