/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.tika.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 *
 * @since Apache Tika 0.8
 */
public class TikaInputStream extends ProxyInputStream {

    /**
     * Casts or wraps the given stream to a TikaInputStream instance.
     * This method can be used to access the functionality of this class
     * even when given just a normal input stream instance.
     *
     * @param stream normal input stream
     * @return a TikaInputStream instance
     */
    public static TikaInputStream get(InputStream stream) {
        if (stream instanceof TikaInputStream) {
            return (TikaInputStream) stream;
        } else {
            return new TikaInputStream(stream);
        }
    }

    /**
     * The file that contains the contents of this stream. This is either
     * the original file passed to the {@link #TikaInputStream(File)}
     * constructor or a temporary file created by a call to the
     * {@link #getFile()} method. If neither has been called, then
     * the value is <code>null</code>.
     */
    private File file;

    /**
     * Flag to indicate that {@link #file} is a temporary file that should
     * be removed when this stream is {@link #close() closed}.
     */
    private boolean temporary;

    /**
     * Current read position within this stream.
     */
    private long position = 0;

    public TikaInputStream(InputStream stream) {
        super(stream);
        this.file = null;
        this.temporary = true;
    }

    public TikaInputStream(File file) {
        super(null);
        this.file = file;
        this.temporary = false;
    }

    public File getFile() throws IOException {
        if (file == null) {
            if (in == null) {
                throw new IOException("Stream has already been read");
            } else if (position > 0) {
                throw new IOException("Stream is already being read");
            } else {
                file = File.createTempFile("apache-tika-", ".tmp");
                OutputStream out = new FileOutputStream(file);
                try {
                    IOUtils.copy(in, out);
                } finally {
                    out.close();
                }
                in.close();
                in = null;
            }
        }
        return file;
    }

    @Override
    public void close() throws IOException {
        if (in != null) {
            in.close();
            in = null;
        }
        if (file != null) {
            if (temporary) {
                file.delete();
            }
            file = null;
        }
    }

    @Override
    protected void beforeRead(int n) throws IOException {
        if (in == null) {
            if (file != null) {
                in = new FileInputStream(file);
            } else {
                throw new IOException("End of the stream reached");
            }
        }
    }

    @Override
    protected void afterRead(int n) throws IOException {
        if (n != -1) {
            position += n;
        } else {
            close();
        }
    }

}

@@ -824,16 +824,53 @@
 ka.io;%0A%0A
+import java.io.ByteArrayInputStream;%0A
 import j
@@ -1031,16 +1031,37 @@
 tStream;
+%0Aimport java.net.URL;
 %0A%0A/**%0A *
@@ -2233,16 +2233,42 @@
 orary;%0A%0A
+    private long length;%0A%0A
     /**%0A
@@ -2357,29 +2357,30 @@
  = 0;%0A%0A    p
-ublic
+rivate
  TikaInputSt
@@ -2394,32 +2394,56 @@
 putStream stream
+, File file, long length
 ) %7B%0A        supe
@@ -2469,28 +2469,28 @@
 this.file = 
-null
+file
 ;%0A        th
@@ -2508,138 +2508,488 @@
 y = 
-true;%0A    %7D%0A%0A    public TikaInputStream(File file) %7B%0A        super(null);%0A        this.file = file
+(file == null);%0A        this.length = length;%0A    %7D%0A%0A    public TikaInputStream(InputStream stream) %7B%0A        this(stream, null, -1);%0A    %7D%0A%0A    public TikaInputStream(byte%5B%5D data) %7B%0A        this(new ByteArrayInputStream(data), null, data.length);%0A    %7D%0A%0A    public TikaInputStream(File file) throws IOException %7B%0A        this(new FileInputStream(file), file, file.length())
 ;%0A    
+%7D%0A%0A
     
-this.temporary = false
+public TikaInputStream(URL url) throws IOException %7B%0A        this(url.openStream(), null, -1)
 ;%0A  
@@ -3674,32 +3674,190 @@
 rn file;%0A    %7D%0A%0A
+    public long getLength() throws IOException %7B%0A        if (length == -1) %7B%0A            length = getFile().length();%0A        %7D%0A        return length;%0A    %7D%0A%0A
     @Override%0A  

Allow passing of files or memory buffers to parsers