Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: non_com/media/jai/codec/MemoryCacheSeekableStream.java


1   /*
2    *  Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
3    *
4    *  Redistribution and use in source and binary forms, with or without
5    *  modification, are permitted provided that the following conditions are met:
6    *
7    *  -Redistributions of source code must retain the above copyright notice, this
8    *  list of conditions and the following disclaimer.
9    *
10   *  -Redistribution in binary form must reproduct the above copyright notice,
11   *  this list of conditions and the following disclaimer in the documentation
12   *  and/or other materials provided with the distribution.
13   *
14   *  Neither the name of Sun Microsystems, Inc. or the names of contributors may
15   *  be used to endorse or promote products derived from this software without
16   *  specific prior written permission.
17   *
18   *  This software is provided "AS IS," without a warranty of any kind. ALL
19   *  EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
20   *  IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
21   *  NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
22   *  LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
23   *  OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
24   *  LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
25   *  INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
26   *  CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
27   *  OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
28   *  POSSIBILITY OF SUCH DAMAGES.
29   *
30   *  You acknowledge that Software is not designed,licensed or intended for use in
31   *  the design, construction, operation or maintenance of any nuclear facility.
32   */
33  package non_com.media.jai.codec;
34  
35  import non_com.media.jai.codec.JaiI18N;
36  import java.io.IOException;
37  import java.io.InputStream;
38  import java.util.Vector;
39  
40  /**
41   *  A subclass of <code>SeekableStream</code> that may be used to wrap a regular
42   *  <code>InputStream</code>. Seeking backwards is supported by means of an
43   *  in-memory cache. For greater efficiency, <code>FileCacheSeekableStream</code>
44   *  should be used in circumstances that allow the creation of a temporary file.
45   *  <p>
46   *
47   *  The <code>mark()</code> and <code>reset()</code> methods are supported. <p>
48   *
49   *  <b> This class is not a committed part of the JAI API. It may be removed or
50   *  changed in future releases of JAI.</b>
51   */
52  public final class MemoryCacheSeekableStream extends SeekableStream {
53  
54    /**
55     *  Log_2 of the sector size.
56     */
57    private final static int SECTOR_SHIFT = 9;
58  
59    /**
60     *  The sector size.
61     */
62    private final static int SECTOR_SIZE = 1 << SECTOR_SHIFT;
63  
64    /**
65     *  A mask to determine the offset within a sector.
66     */
67    private final static int SECTOR_MASK = SECTOR_SIZE - 1;
68  
69    /**
70     *  Number of sectors stored.
71     */
72    int sectors = 0;
73  
74    /**
75     *  Number of bytes read.
76     */
77    int length = 0;
78  
79    /**
80     *  True if we've previously reached the end of the source stream
81     */
82    boolean foundEOS = false;
83  
84    /**
85     *  The source input stream.
86     */
87    private InputStream src;
88  
89    /**
90     *  Position of first unread byte.
91     */
92    private long pointer = 0;
93  
94    /**
95     *  A Vector of source sectors.
96     */
97    private Vector data = new Vector();
98  
99  
100   /**
101    *  Constructs a <code>MemoryCacheSeekableStream</code> that takes its source
102    *  data from a regular <code>InputStream</code>. Seeking backwards is
103    *  supported by means of an in-memory cache.
104    *
105    * @param  src  Description of Parameter
106    */
107   public MemoryCacheSeekableStream(InputStream src) {
108     this.src = src;
109   }
110 
111 
112   /**
113    *  Returns the current offset in this file.
114    *
115    * @return    the offset from the beginning of the file, in bytes, at which
116    *      the next read occurs.
117    */
118   public long getFilePointer() {
119     return pointer;
120   }
121 
122 
123   /**
124    *  Returns <code>true</code> since all <code>MemoryCacheSeekableStream</code>
125    *  instances support seeking backwards.
126    *
127    * @return    Description of the Returned Value
128    */
129   public boolean canSeekBackwards() {
130     return true;
131   }
132 
133 
134   /**
135    *  Sets the file-pointer offset, measured from the beginning of this file, at
136    *  which the next read occurs.
137    *
138    * @param  pos              the offset position, measured in bytes from the
139    *      beginning of the file, at which to set the file pointer.
140    * @exception  IOException  if <code>pos</code> is less than <code>0</code> or
141    *      if an I/O error occurs.
142    */
143   public void seek(long pos) throws IOException {
144     if (pos < 0) {
145       throw new IOException(JaiI18N.getString("MemoryCacheSeekableStream0"));
146     }
147     pointer = pos;
148   }
149 
150 
151   /**
152    *  Reads the next byte of data from the input stream. The value byte is
153    *  returned as an <code>int</code> in the range <code>0</code> to <code>255</code>
154    *  . If no byte is available because the end of the stream has been reached,
155    *  the value <code>-1</code> is returned. This method blocks until input data
156    *  is available, the end of the stream is detected, or an exception is
157    *  thrown.
158    *
159    * @return                  the next byte of data, or <code>-1</code> if the
160    *      end of the stream is reached.
161    * @exception  IOException  Description of Exception
162    */
163   public int read() throws IOException {
164     long next = pointer + 1;
165     long pos = readUntil(next);
166     if (pos >= next) {
167       byte[] buf =
168           (byte[]) data.elementAt((int) (pointer >> SECTOR_SHIFT));
169       return buf[(int) (pointer++ & SECTOR_MASK)] & 0xff;
170     }
171     else {
172       return -1;
173     }
174   }
175 
176 
177   /**
178    *  Reads up to <code>len</code> bytes of data from the input stream into an
179    *  array of bytes. An attempt is made to read as many as <code>len</code>
180    *  bytes, but a smaller number may be read, possibly zero. The number of
181    *  bytes actually read is returned as an integer. <p>
182    *
183    *  This method blocks until input data is available, end of file is detected,
184    *  or an exception is thrown. <p>
185    *
186    *  If <code>b</code> is <code>null</code>, a <code>NullPointerException</code>
187    *  is thrown. <p>
188    *
189    *  If <code>off</code> is negative, or <code>len</code> is negative, or
190    *  <code>off+len</code> is greater than the length of the array <code>b</code>
191    *  , then an <code>IndexOutOfBoundsException</code> is thrown. <p>
192    *
193    *  If <code>len</code> is zero, then no bytes are read and <code>0</code> is
194    *  returned; otherwise, there is an attempt to read at least one byte. If no
195    *  byte is available because the stream is at end of file, the value <code>-1</code>
196    *  is returned; otherwise, at least one byte is read and stored into <code>b</code>
197    *  . <p>
198    *
199    *  The first byte read is stored into element <code>b[off]</code>, the next
200    *  one into <code>b[off+1]</code>, and so on. The number of bytes read is, at
201    *  most, equal to <code>len</code>. Let <i>k</i> be the number of bytes
202    *  actually read; these bytes will be stored in elements <code>b[off]</code>
203    *  through <code>b[off+</code><i>k</i> <code>-1]</code>, leaving elements
204    *  <code>b[off+</code><i>k</i> <code>]</code> through <code>b[off+len-1]</code>
205    *  unaffected. <p>
206    *
207    *  In every case, elements <code>b[0]</code> through <code>b[off]</code> and
208    *  elements <code>b[off+len]</code> through <code>b[b.length-1]</code> are
209    *  unaffected. <p>
210    *
211    *  If the first byte cannot be read for any reason other than end of file,
212    *  then an <code>IOException</code> is thrown. In particular, an <code>IOException</code>
213    *  is thrown if the input stream has been closed.
214    *
215    * @param  b                the buffer into which the data is read.
216    * @param  off              the start offset in array <code>b</code> at which
217    *      the data is written.
218    * @param  len              the maximum number of bytes to read.
219    * @return                  the total number of bytes read into the buffer, or
220    *      <code>-1</code> if there is no more data because the end of the stream
221    *      has been reached.
222    * @exception  IOException  Description of Exception
223    */
224   public int read(byte[] b, int off, int len) throws IOException {
225     if (b == null) {
226       throw new NullPointerException();
227     }
228     if ((off < 0) || (len < 0) || (off + len > b.length)) {
229       throw new IndexOutOfBoundsException();
230     }
231     if (len == 0) {
232       return 0;
233     }
234 
235     long pos = readUntil(pointer + len);
236     // End-of-stream
237     if (pos <= pointer) {
238       return -1;
239     }
240 
241     byte[] buf = (byte[]) data.elementAt((int) (pointer >> SECTOR_SHIFT));
242     int nbytes = Math.min(len, SECTOR_SIZE - (int) (pointer & SECTOR_MASK));
243     System.arraycopy(buf, (int) (pointer & SECTOR_MASK),
244         b, off, nbytes);
245     pointer += nbytes;
246     return nbytes;
247   }
248 
249 
250   /**
251    *  Ensures that at least <code>pos</code> bytes are cached, or the end of the
252    *  source is reached. The return value is equal to the smaller of <code>pos</code>
253    *  and the length of the source stream.
254    *
255    * @param  pos              Description of Parameter
256    * @return                  Description of the Returned Value
257    * @exception  IOException  Description of Exception
258    */
259   private long readUntil(long pos) throws IOException {
260     // We've already got enough data cached
261     if (pos < length) {
262       return pos;
263     }
264     // pos >= length but length isn't getting any bigger, so return it
265     if (foundEOS) {
266       return length;
267     }
268 
269     int sector = (int) (pos >> SECTOR_SHIFT);
270 
271     // First unread sector
272     int startSector = length >> SECTOR_SHIFT;
273 
274     // Read sectors until the desired sector
275     for (int i = startSector; i <= sector; i++) {
276       byte[] buf = new byte[SECTOR_SIZE];
277       data.addElement(buf);
278 
279       // Read up to SECTOR_SIZE bytes
280       int len = SECTOR_SIZE;
281       int off = 0;
282       while (len > 0) {
283         int nbytes = src.read(buf, off, len);
284         // Found the end-of-stream
285         if (nbytes == -1) {
286           foundEOS = true;
287           return length;
288         }
289         off += nbytes;
290         len -= nbytes;
291 
292         // Record new data length
293         length += nbytes;
294       }
295     }
296 
297     return length;
298   }
299 }