Package com.sun.media.imageio.stream

Source Code of com.sun.media.imageio.stream.FileChannelImageInputStream

/*
* $RCSfile: FileChannelImageInputStream.java,v $
*
*
* Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
*   notice, this  list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
*   notice, this list of conditions and the following disclaimer in
*   the documentation and/or other materials provided with the
*   distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for
* use in the design, construction, operation or maintenance of any
* nuclear facility.
*
* $Revision: 1.2 $
* $Date: 2007/09/14 22:57:55 $
* $State: Exp $
*/
package com.sun.media.imageio.stream;

import java.io.File;
import java.io.EOFException;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.MappedByteBuffer;
import java.nio.ShortBuffer;
import java.nio.channels.FileChannel;
import javax.imageio.stream.ImageInputStreamImpl;

/**
* A class which implements <code>ImageInputStream</code> using a
* <code>FileChannel</code> as the eventual data source. The channel
* contents are assumed to be stable during the lifetime of the object.
*
* <p>Memory mapping and new I/O view <code>Buffer</code>s are used to
* read the data. Only methods which provide significant performance
* improvement with respect to the superclass implementation are overridden.
* Overridden methods are not commented individually unless some noteworthy
* aspect of the implementation must be described.</p>
*
* <p>The methods of this class are <b>not</b> synchronized.</p>
*
* @see javax.imageio.stream.ImageInputStream
* @see java.nio
* @see java.nio.channels.FileChannel
*/
public class FileChannelImageInputStream extends ImageInputStreamImpl {

    /** The <code>FileChannel</code> data source. */
    private FileChannel channel;

    /** A memory mapping of all or part of the channel. */
    private MappedByteBuffer mappedBuffer;

    /** The stream position of the mapping. */
    private long mappedPos;

    /** The stream position least upper bound of the mapping. */
    private long mappedUpperBound;

    /**
     * Constructs a <code>FileChannelImageInputStream</code> from a
     * <code>FileChannel</code>.  The initial position of the stream
     * stream is taken to be the position of the <code>FileChannel</code>
     * parameter when this constructor is invoked.  The stream and flushed
     * positions are therefore both initialized to
     * <code>channel.position()</code>.
     *
     * @param channel the source <code>FileChannel</code>.
     *
     * @throws IllegalArgumentException if <code>channel</code> is
     *         <code>null</code> or is not open.
     * @throws IOException if a method invoked on <code>channel</code>
     *         throws an <code>IOException</code>.
     */
    public FileChannelImageInputStream(FileChannel channel)
        throws IOException {

        // Check the parameter.
        if(channel == null) {
            throw new IllegalArgumentException("channel == null");
        } else if(!channel.isOpen()) {
            throw new IllegalArgumentException("channel.isOpen() == false");
        }

        // Save the channel reference.
        this.channel = channel;

        // Get the channel position.
  long channelPosition = channel.position();

        // Set stream and flushed positions to initial channel position.
        this.streamPos = this.flushedPos = channelPosition;

        // Determine the size of the mapping.
        long fullSize = channel.size() - channelPosition;
        long mappedSize = Math.min(fullSize, Integer.MAX_VALUE);

        // Set the mapped position and upper bound.
        this.mappedPos = 0;
        this.mappedUpperBound = mappedPos + mappedSize;

        // Map the file.
  this.mappedBuffer = channel.map(FileChannel.MapMode.READ_ONLY,
                                        channelPosition,
                                        mappedSize);
    }

    /**
     * Returns a <code>MappedByteBuffer</code> which memory maps
     * at least from the channel position corresponding to the
     * current stream position to <code>len</code> bytes beyond.
     * A new buffer is created only if necessary.
     *
     * @param len The number of bytes required beyond the current stream
     * position.
     */
    private MappedByteBuffer getMappedBuffer(int len) throws IOException {
        // If request is outside mapped region, map a new region.
        if(streamPos < mappedPos || streamPos + len >= mappedUpperBound) {

            // Set the map position.
            mappedPos = streamPos;

            // Determine the map size.
            long mappedSize = Math.min(channel.size() - mappedPos,
                                       Integer.MAX_VALUE);

            // Set the mapped upper bound.
            mappedUpperBound = mappedPos + mappedSize;

            // Map the file.
            mappedBuffer = channel.map(FileChannel.MapMode.READ_ONLY,
                                       mappedPos,
                                       mappedSize);
           
            mappedBuffer.order(super.getByteOrder());

        }
       
        return mappedBuffer;
    }

    // --- Implementation of superclass abstract methods. ---

    public int read() throws IOException {
        checkClosed();
        bitOffset = 0;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(1);

        // Check number of bytes left.
        if(byteBuffer.remaining() < 1) {
            // Return EOF.
            return -1;
        }

        // Get the byte from the buffer.
  int value = byteBuffer.get()&0xff;

        // Increment the stream position.
  streamPos++;

  //System.out.println("value = "+value);

  return value;
    }

    public int read(byte[] b, int off, int len) throws IOException {
        if(off < 0 || len < 0 || off + len > b.length) {
            // NullPointerException will be thrown before this if b is null.
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off + len > b.length");
        } else if(len == 0) {
            return 0;
        }

        checkClosed();
        bitOffset = 0;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(len);

        // Get the number of bytes remaining.
        int numBytesRemaining = byteBuffer.remaining();

        // Check number of bytes left.
        if(numBytesRemaining < 1) {
            // Return EOF.
            return -1;
        } else if(len > numBytesRemaining) {
            // Clamp 'len' to number of bytes in Buffer. Apparently some
            // readers (JPEG) request data beyond the end of the file.
            len = numBytesRemaining;
        }

        // Read the data from the buffer.
        byteBuffer.get(b, off, len);

        // Increment the stream position.
  streamPos += len;

  return len;
    }

    // --- Overriding of superclass methods. ---

    /**
     * Invokes the superclass method and sets the internal reference
     * to the source <code>FileChannel</code> to <code>null</code>.
     * The source <code>FileChannel</code> is not closed.
     *
     * @exception IOException if an error occurs.
     */
    public void close() throws IOException {
        super.close();
        channel = null;
    }

    public void readFully(char[] c, int off, int len) throws IOException {
        if(off < 0 || len < 0 || off + len > c.length) {
            // NullPointerException will be thrown before this if c is null.
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off + len > c.length");
        } else if(len == 0) {
            return;
        }

        // Determine the requested length in bytes.
        int byteLen = 2*len;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(byteLen);

        // Ensure enough bytes remain.
        if(byteBuffer.remaining() < byteLen) {
            throw new EOFException();
        }

        // Get the view Buffer.
        CharBuffer viewBuffer = byteBuffer.asCharBuffer();

        // Get the chars.
        viewBuffer.get(c, off, len);

        // Update the position.
        seek(streamPos + byteLen);
    }

    public void readFully(short[] s, int off, int len) throws IOException {
        if(off < 0 || len < 0 || off + len > s.length) {
            // NullPointerException will be thrown before this if s is null.
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off + len > s.length");
        } else if(len == 0) {
            return;
        }

        // Determine the requested length in bytes.
        int byteLen = 2*len;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(byteLen);

        // Ensure enough bytes remain.
        if(byteBuffer.remaining() < byteLen) {
            throw new EOFException();
        }

        // Get the view Buffer.
        ShortBuffer viewBuffer = byteBuffer.asShortBuffer();

        // Get the shorts.
        viewBuffer.get(s, off, len);

        // Update the position.
        seek(streamPos + byteLen);
    }

    public void readFully(int[] i, int off, int len) throws IOException {
        if(off < 0 || len < 0 || off + len > i.length) {
            // NullPointerException will be thrown before this if i is null.
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off + len > i.length");
        } else if(len == 0) {
            return;
        }

        // Determine the requested length in bytes.
        int byteLen = 4*len;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(byteLen);

        // Ensure enough bytes remain.
        if(byteBuffer.remaining() < byteLen) {
            throw new EOFException();
        }

        // Get the view Buffer.
        IntBuffer viewBuffer = byteBuffer.asIntBuffer();

        // Get the ints.
        viewBuffer.get(i, off, len);

        // Update the position.
        seek(streamPos + byteLen);
    }

    public void readFully(long[] l, int off, int len) throws IOException {
        if(off < 0 || len < 0 || off + len > l.length) {
            // NullPointerException will be thrown before this if l is null.
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off + len > l.length");
        } else if(len == 0) {
            return;
        }

        // Determine the requested length in bytes.
        int byteLen = 8*len;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(byteLen);

        // Ensure enough bytes remain.
        if(byteBuffer.remaining() < byteLen) {
            throw new EOFException();
        }

        // Get the view Buffer.
        LongBuffer viewBuffer = byteBuffer.asLongBuffer();

        // Get the longs.
        viewBuffer.get(l, off, len);

        // Update the position.
        seek(streamPos + byteLen);
    }

    public void readFully(float[] f, int off, int len) throws IOException {
        if(off < 0 || len < 0 || off + len > f.length) {
            // NullPointerException will be thrown before this if f is null.
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off + len > f.length");
        } else if(len == 0) {
            return;
        }

        // Determine the requested length in bytes.
        int byteLen = 4*len;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(byteLen);

        // Ensure enough bytes remain.
        if(byteBuffer.remaining() < byteLen) {
            throw new EOFException();
        }

        // Get the view Buffer.
        FloatBuffer viewBuffer = byteBuffer.asFloatBuffer();

        // Get the floats.
        viewBuffer.get(f, off, len);

        // Update the position.
        seek(streamPos + byteLen);
    }

    public void readFully(double[] d, int off, int len) throws IOException {
        if(off < 0 || len < 0 || off + len > d.length) {
            // NullPointerException will be thrown before this if d is null.
            throw new IndexOutOfBoundsException
                ("off < 0 || len < 0 || off + len > d.length");
        } else if(len == 0) {
            return;
        }

        // Determine the requested length in bytes.
        int byteLen = 8*len;

        // Get the mapped buffer.
  ByteBuffer byteBuffer = getMappedBuffer(byteLen);

        // Ensure enough bytes remain.
        if(byteBuffer.remaining() < byteLen) {
            throw new EOFException();
        }

        // Get the view Buffer.
        DoubleBuffer viewBuffer = byteBuffer.asDoubleBuffer();

        // Get the doubles.
        viewBuffer.get(d, off, len);

        // Update the position.
        seek(streamPos + byteLen);
    }

    /**
     * Returns the number of bytes currently in the <code>FileChannel</code>.
     * If an <code>IOException</code> is encountered when querying the
     * channel's size, -1L will be returned.
     *
     * @return The number of bytes in the channel
     * -1L to indicate unknown length.
     */
    public long length() {
        // Initialize to value indicating unknown length.
        long length = -1L;

        // Set length to current size with respect to initial position.
        try {
            length = channel.size();
        } catch(IOException e) {
            // Default to unknown length.
        }

        return length;
    }

    /**
     * Invokes the superclass method and sets the position within the
     * memory mapped buffer.  A new region is mapped if necessary.  The
     * position of the source <code>FileChannel</code> is not changed, i.e.,
     * {@link java.nio.channels.FileChannel#position(long)} is not invoked.
     */
    public void seek(long pos) throws IOException {
        super.seek(pos);

        if(pos >= mappedPos && pos < mappedUpperBound) {
            // Seeking to location within mapped buffer: set buffer position.
            mappedBuffer.position((int)(pos - mappedPos));
        } else {
            // Seeking to location outside mapped buffer: get a new mapped
            // buffer at current position with maximal size.
            int len = (int)Math.min(channel.size() - pos, Integer.MAX_VALUE);
            mappedBuffer = getMappedBuffer(len);
        }
    }

    public void setByteOrder(ByteOrder networkByteOrder) {
        super.setByteOrder(networkByteOrder);
        mappedBuffer.order(networkByteOrder);
    }
}
TOP

Related Classes of com.sun.media.imageio.stream.FileChannelImageInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.