001/*002 * $RCSfile: SegmentedImageInputStream.java,v $003 *004 * 005 * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.006 * 007 * Redistribution and use in source and binary forms, with or without008 * modification, are permitted provided that the following conditions009 * are met: 010 * 011 * - Redistribution of source code must retain the above copyright 012 *   notice, this  list of conditions and the following disclaimer.013 * 014 * - Redistribution in binary form must reproduce the above copyright015 *   notice, this list of conditions and the following disclaimer in 016 *   the documentation and/or other materials provided with the017 *   distribution.018 * 019 * Neither the name of Sun Microsystems, Inc. or the names of 020 * contributors may be used to endorse or promote products derived 021 * from this software without specific prior written permission.022 * 023 * This software is provided "AS IS," without a warranty of any 024 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 025 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 026 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY027 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 028 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 029 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS030 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 031 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,032 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND033 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR034 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE035 * POSSIBILITY OF SUCH DAMAGES. 036 * 037 * You acknowledge that this software is not designed or intended for 038 * use in the design, construction, operation or maintenance of any 039 * nuclear facility. 040 *041 * $Revision: 1.2 $042 * $Date: 2007/08/28 01:12:56 $043 * $State: Exp $044 */045package com.github.jaiimageio.stream;046047import java.io.IOException;048049import javax.imageio.stream.ImageInputStream;050import javax.imageio.stream.ImageInputStreamImpl;051052/**053 * An implementation of the <code>StreamSegmentMapper</code> interface054 * that requires an explicit list of the starting locations and055 * lengths of the source segments.056 */057class StreamSegmentMapperImpl implements StreamSegmentMapper {058059    private long[] segmentPositions;060061    private int[] segmentLengths;062063    public StreamSegmentMapperImpl(long[] segmentPositions,064                                   int[] segmentLengths) {065        this.segmentPositions = (long[])segmentPositions.clone();066        this.segmentLengths = (int[])segmentLengths.clone();067    }068069    public StreamSegment getStreamSegment(long position, int length) {070        int numSegments = segmentLengths.length;071        for (int i = 0; i < numSegments; i++) {072            int len = segmentLengths[i];073            if (position < len) {074                return new StreamSegment(segmentPositions[i] + position,075                                         Math.min(len - (int)position,076                                                  length));077            }078            position -= len;079        }080081        return null;082    }083084    public void getStreamSegment(long position, int length,085                                 StreamSegment seg) {086        int numSegments = segmentLengths.length;087        for (int i = 0; i < numSegments; i++) {088            int len = segmentLengths[i];089            if (position < len) {090                seg.setStartPos(segmentPositions[i] + position);091                seg.setSegmentLength(Math.min(len - (int)position, length));092                return;093            }094            position -= len;095        }096097        seg.setStartPos(-1);098        seg.setSegmentLength(-1);099        return;100    }101102    long length() {103        int numSegments = segmentLengths.length;104        long len = 0L;105106        for(int i = 0; i < numSegments; i++) {107            len += segmentLengths[i];108        }109110        return len;111    }112}113114/**115 * An implementation of the <code>StreamSegmentMapper</code> interface116 * for segments of equal length.117 */118class SectorStreamSegmentMapper implements StreamSegmentMapper {119120    long[] segmentPositions;121    int segmentLength;122    int totalLength;123    int lastSegmentLength;124125    public SectorStreamSegmentMapper(long[] segmentPositions,126                                     int segmentLength,127                                     int totalLength) {128        this.segmentPositions = (long[])segmentPositions.clone();129        this.segmentLength = segmentLength;130        this.totalLength = totalLength;131        this.lastSegmentLength = totalLength -132            (segmentPositions.length - 1)*segmentLength;133    }134135    public StreamSegment getStreamSegment(long position, int length) {136        int index = (int) (position/segmentLength);137138        // Compute segment length139        int len = (index == segmentPositions.length - 1) ?140            lastSegmentLength : segmentLength;141142        // Compute position within the segment143        position -= index*segmentLength;144145        // Compute maximum legal length146        len -= position;147        if (len > length) {148            len = length;149        }150        return new StreamSegment(segmentPositions[index] + position, len);151    }152153    public void getStreamSegment(long position, int length,154                                 StreamSegment seg) {155        int index = (int) (position/segmentLength);156157        // Compute segment length158        int len = (index == segmentPositions.length - 1) ?159            lastSegmentLength : segmentLength;160161        // Compute position within the segment162        position -= index*segmentLength;163164        // Compute maximum legal length165        len -= position;166        if (len > length) {167            len = length;168        }169170        seg.setStartPos(segmentPositions[index] + position);171        seg.setSegmentLength(len);172    }173174    long length() {175        return (long)totalLength;176    }177}178179/**180 * A <code>SegmentedImageInputStream</code> provides a view of a181 * subset of another <code>ImageInputStream</code> consiting of a series182 * of segments with given starting positions in the source stream and183 * lengths.  The resulting stream behaves like an ordinary184 * <code>ImageInputStream</code>.185 *186 * <p> For example, given a <code>ImageInputStream</code> containing187 * data in a format consisting of a number of sub-streams stored in188 * non-contiguous sectors indexed by a directory, it is possible to189 * construct a set of <code>SegmentedImageInputStream</code>s, one for190 * each sub-stream, that each provide a view of the sectors comprising191 * a particular stream by providing the positions and lengths of the192 * stream's sectors as indicated by the directory.  The complex193 * multi-stream structure of the original stream may be ignored by194 * users of the <code>SegmentedImageInputStream</code>, who see a195 * separate <code>ImageInputStream</code> for each sub-stream and do not196 * need to understand the directory structure at all.197 *198 * <p> For further efficiency, a directory structure such as in the199 * example described above need not be fully parsed in order to build200 * a <code>SegmentedImageInputStream</code>.  Instead, the201 * <code>StreamSegmentMapper</code> interface allows the association202 * between a desired region of the output and an input segment to be203 * provided dynamically.  This mapping might be computed by reading204 * from a directory in piecemeal fashion in order to avoid consuming205 * memory resources.206 */207public class SegmentedImageInputStream extends ImageInputStreamImpl {208209    private ImageInputStream stream;210    private StreamSegmentMapper mapper;211    212    /**213     * Constructs a <code>SegmentedImageInputStream</code>214     * given a <code>ImageInputStream</code> as input215     * and an instance of <code>StreamSegmentMapper</code>.216     *217     * @param stream A source <code>ImageInputStream</code>218     * @param mapper An instance of the <code>StreamSegmentMapper</code>219     *        interface.220     */221    public SegmentedImageInputStream(ImageInputStream stream,222                                     StreamSegmentMapper mapper) {223        super();224225        this.stream = stream;226        this.mapper = mapper;227    }228229    /**230     * Constructs a <code>SegmentedImageInputStream</code> given a231     * <code>ImageInputStream</code> as input and a list of the starting232     * positions and lengths of the segments of the source stream.233     *234     * @param stream A source <code>ImageInputStream</code>235     * @param segmentPositions An array of <code>long</code>s 236     *        giving the starting positions of the segments in the237     *        source stream.238     * @param segmentLengths  An array of <code>int</code>s 239     *        giving the lengths of segments in the source stream.240     */241    public SegmentedImageInputStream(ImageInputStream stream,242                                     long[] segmentPositions,243                                     int[] segmentLengths) {244        this(stream,245             new StreamSegmentMapperImpl(segmentPositions, segmentLengths));246    }247248    /**249     * Constructs a <code>SegmentedImageInputStream</code> given a250     * <code>ImageInputStream</code> as input, a list of the starting251     * positions of the segments of the source stream, the common252     * length of each segment, and the total length of the segments.253     *254     * <p> This constructor is useful for selecting substreams255     *     of sector-oriented file formats in which each segment256     *     of the substream (except possibly the final segment)257     *     occupies a fixed-length sector.258     *259     * @param stream A source <code>ImageInputStream</code>260     * @param segmentPositions An array of <code>long</code>s 261     *        giving the starting positions of the segments in the262     *        source stream.263     * @param segmentLength  The common length of each segment.264     * @param totalLength  The total length of the source segments.265     */266    public SegmentedImageInputStream(ImageInputStream stream,267                                     long[] segmentPositions,268                                     int segmentLength,269                                     int totalLength) {270        this(stream,271             new SectorStreamSegmentMapper(segmentPositions,272                                           segmentLength,273                                           totalLength));274    }275276    private StreamSegment streamSegment = new StreamSegment();277    278    /**279     * Reads the next byte of data from the input stream. The value byte is280     * returned as an <code>int</code> in the range <code>0</code> to281     * <code>255</code>. If no byte is available because the end of the stream282     * has been reached, the value <code>-1</code> is returned. This method283     * blocks until input data is available, the end of the stream is detected,284     * or an exception is thrown.285     *286     * @return     the next byte of data, or <code>-1</code> if the end of the287     *             stream is reached.288     * @exception  IOException  if an I/O error occurs.289     */290    public int read() throws IOException {291        mapper.getStreamSegment(streamPos, 1, streamSegment);292        int streamSegmentLength = streamSegment.getSegmentLength();293        if(streamSegmentLength < 0) {294            return -1;295        }296        stream.seek(streamSegment.getStartPos());297298        // XXX What happens if streamSegmentLength == 0? Should this299        // method also return -1 as above for streamSegmentLength < 0?300        int val = stream.read();301        ++streamPos;302        return val;303    }304305    /**306     * Reads up to <code>len</code> bytes of data from the input stream into307     * an array of bytes.  An attempt is made to read as many as308     * <code>len</code> bytes, but a smaller number may be read, possibly309     * zero. The number of bytes actually read is returned as an integer.310     *311     * <p> This method blocks until input data is available, end of stream is312     * detected, or an exception is thrown.313     *314     * <p> If <code>b</code> is <code>null</code>, a315     * <code>NullPointerException</code> is thrown.316     *317     * <p> If <code>off</code> is negative, or <code>len</code> is negative, or318     * <code>off+len</code> is greater than the length of the array319     * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is320     * thrown.321     *322     * <p> If <code>len</code> is zero, then no bytes are read and323     * <code>0</code> is returned; otherwise, there is an attempt to read at324     * least one byte. If no byte is available because the stream is at end of325     * stream, the value <code>-1</code> is returned; otherwise, at least one326     * byte is read and stored into <code>b</code>.327     *328     * <p> The first byte read is stored into element <code>b[off]</code>, the329     * next one into <code>b[off+1]</code>, and so on. The number of bytes read330     * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of331     * bytes actually read; these bytes will be stored in elements332     * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,333     * leaving elements <code>b[off+</code><i>k</i><code>]</code> through334     * <code>b[off+len-1]</code> unaffected.335     *336     * <p> In every case, elements <code>b[0]</code> through337     * <code>b[off]</code> and elements <code>b[off+len]</code> through338     * <code>b[b.length-1]</code> are unaffected.339     *340     * <p> If the first byte cannot be read for any reason other than end of341     * stream, then an <code>IOException</code> is thrown. In particular, an342     * <code>IOException</code> is thrown if the input stream has been closed.343     *344     * @param      b     the buffer into which the data is read.345     * @param      off   the start offset in array <code>b</code>346     *                   at which the data is written.347     * @param      len   the maximum number of bytes to read.348     * @return     the total number of bytes read into the buffer, or349     *             <code>-1</code> if there is no more data because the end of350     *             the stream has been reached.351     * @exception  IOException  if an I/O error occurs.352     */353    public int read(byte[] b, int off, int len) throws IOException {354        if (b == null) {355            throw new NullPointerException();356        }357        if ((off < 0) || (len < 0) || (off + len > b.length)) {358            throw new IndexOutOfBoundsException();359        }360        if (len == 0) {361            return 0;362        }363364        mapper.getStreamSegment(streamPos, len, streamSegment);365        int streamSegmentLength = streamSegment.getSegmentLength();366        if(streamSegmentLength < 0) {367            return -1;368        }369        stream.seek(streamSegment.getStartPos());370371        int nbytes = stream.read(b, off, streamSegmentLength);372        streamPos += nbytes;373        return nbytes;374    }375376    public long length() {377        long len;378        if(mapper instanceof StreamSegmentMapperImpl) {379            len = ((StreamSegmentMapperImpl)mapper).length();380        } else if(mapper instanceof SectorStreamSegmentMapper) {381            len = ((SectorStreamSegmentMapper)mapper).length();382        } else if(mapper != null) {383            long pos = len = 0L;384            StreamSegment seg = mapper.getStreamSegment(pos, Integer.MAX_VALUE);385            while((len = seg.getSegmentLength()) > 0) {386                pos += len;387                seg.setSegmentLength(0);388                mapper.getStreamSegment(pos, Integer.MAX_VALUE, seg);389            }390            len = pos;391        } else {392            len = super.length();393        }394395        return len;396    }397}


NOTHING
NOTHING
Add the Maven Dependecy to your project: maven dependecy for com.amazonaws : aws-java-sdk : 1.3.14