Save This Page
Home » openjdk-7 » javax » imageio » stream » [javadoc | source]
    1   /*
    2    * Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.imageio.stream;
   27   
   28   import java.io.File;
   29   import java.io.IOException;
   30   import java.io.OutputStream;
   31   import java.io.RandomAccessFile;
   32   import com.sun.imageio.stream.StreamCloser;
   33   
   34   /**
   35    * An implementation of <code>ImageOutputStream</code> that writes its
   36    * output to a regular <code>OutputStream</code>.  A file is used to
   37    * cache data until it is flushed to the output stream.
   38    *
   39    */
   40   public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
   41   
   42       private OutputStream stream;
   43   
   44       private File cacheFile;
   45   
   46       private RandomAccessFile cache;
   47   
   48       // Pos after last (rightmost) byte written
   49       private long maxStreamPos = 0L;
   50   
   51       /**
   52        * Constructs a <code>FileCacheImageOutputStream</code> that will write
   53        * to a given <code>outputStream</code>.
   54        *
   55        * <p> A temporary file is used as a cache.  If
   56        * <code>cacheDir</code>is non-<code>null</code> and is a
   57        * directory, the file will be created there.  If it is
   58        * <code>null</code>, the system-dependent default temporary-file
   59        * directory will be used (see the documentation for
   60        * <code>File.createTempFile</code> for details).
   61        *
   62        * @param stream an <code>OutputStream</code> to write to.
   63        * @param cacheDir a <code>File</code> indicating where the
   64        * cache file should be created, or <code>null</code> to use the
   65        * system directory.
   66        *
   67        * @exception IllegalArgumentException if <code>stream</code>
   68        * is <code>null</code>.
   69        * @exception IllegalArgumentException if <code>cacheDir</code> is
   70        * non-<code>null</code> but is not a directory.
   71        * @exception IOException if a cache file cannot be created.
   72        */
   73       public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
   74           throws IOException {
   75           if (stream == null) {
   76               throw new IllegalArgumentException("stream == null!");
   77           }
   78           if ((cacheDir != null) && !(cacheDir.isDirectory())) {
   79               throw new IllegalArgumentException("Not a directory!");
   80           }
   81           this.stream = stream;
   82           this.cacheFile =
   83               File.createTempFile("imageio", ".tmp", cacheDir);
   84           this.cache = new RandomAccessFile(cacheFile, "rw");
   85           StreamCloser.addToQueue(this);
   86       }
   87   
   88       public int read() throws IOException {
   89           checkClosed();
   90           bitOffset = 0;
   91           int val =  cache.read();
   92           if (val != -1) {
   93               ++streamPos;
   94           }
   95           return val;
   96       }
   97   
   98       public int read(byte[] b, int off, int len) throws IOException {
   99           checkClosed();
  100   
  101           if (b == null) {
  102               throw new NullPointerException("b == null!");
  103           }
  104           if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
  105               throw new IndexOutOfBoundsException
  106                   ("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
  107           }
  108   
  109           bitOffset = 0;
  110   
  111           if (len == 0) {
  112               return 0;
  113           }
  114   
  115           int nbytes = cache.read(b, off, len);
  116           if (nbytes != -1) {
  117               streamPos += nbytes;
  118           }
  119           return nbytes;
  120       }
  121   
  122       public void write(int b) throws IOException {
  123           flushBits(); // this will call checkClosed() for us
  124           cache.write(b);
  125           ++streamPos;
  126           maxStreamPos = Math.max(maxStreamPos, streamPos);
  127       }
  128   
  129       public void write(byte[] b, int off, int len) throws IOException {
  130           flushBits(); // this will call checkClosed() for us
  131           cache.write(b, off, len);
  132           streamPos += len;
  133           maxStreamPos = Math.max(maxStreamPos, streamPos);
  134       }
  135   
  136       public long length() {
  137           try {
  138               checkClosed();
  139               return cache.length();
  140           } catch (IOException e) {
  141               return -1L;
  142           }
  143       }
  144   
  145       /**
  146        * Sets the current stream position and resets the bit offset to
  147        * 0.  It is legal to seek past the end of the file; an
  148        * <code>EOFException</code> will be thrown only if a read is
  149        * performed.  The file length will not be increased until a write
  150        * is performed.
  151        *
  152        * @exception IndexOutOfBoundsException if <code>pos</code> is smaller
  153        * than the flushed position.
  154        * @exception IOException if any other I/O error occurs.
  155        */
  156       public void seek(long pos) throws IOException {
  157           checkClosed();
  158   
  159           if (pos < flushedPos) {
  160               throw new IndexOutOfBoundsException();
  161           }
  162   
  163           cache.seek(pos);
  164           this.streamPos = cache.getFilePointer();
  165           maxStreamPos = Math.max(maxStreamPos, streamPos);
  166           this.bitOffset = 0;
  167       }
  168   
  169       /**
  170        * Returns <code>true</code> since this
  171        * <code>ImageOutputStream</code> caches data in order to allow
  172        * seeking backwards.
  173        *
  174        * @return <code>true</code>.
  175        *
  176        * @see #isCachedMemory
  177        * @see #isCachedFile
  178        */
  179       public boolean isCached() {
  180           return true;
  181       }
  182   
  183       /**
  184        * Returns <code>true</code> since this
  185        * <code>ImageOutputStream</code> maintains a file cache.
  186        *
  187        * @return <code>true</code>.
  188        *
  189        * @see #isCached
  190        * @see #isCachedMemory
  191        */
  192       public boolean isCachedFile() {
  193           return true;
  194       }
  195   
  196       /**
  197        * Returns <code>false</code> since this
  198        * <code>ImageOutputStream</code> does not maintain a main memory
  199        * cache.
  200        *
  201        * @return <code>false</code>.
  202        *
  203        * @see #isCached
  204        * @see #isCachedFile
  205        */
  206       public boolean isCachedMemory() {
  207           return false;
  208       }
  209   
  210       /**
  211        * Closes this <code>FileCacheImageOututStream</code>.  All
  212        * pending data is flushed to the output, and the cache file
  213        * is closed and removed.  The destination <code>OutputStream</code>
  214        * is not closed.
  215        *
  216        * @exception IOException if an error occurs.
  217        */
  218       public void close() throws IOException {
  219           maxStreamPos = cache.length();
  220   
  221           seek(maxStreamPos);
  222           flushBefore(maxStreamPos);
  223           super.close();
  224           cache.close();
  225           cache = null;
  226           cacheFile.delete();
  227           cacheFile = null;
  228           stream.flush();
  229           stream = null;
  230           StreamCloser.removeFromQueue(this);
  231       }
  232   
  233       public void flushBefore(long pos) throws IOException {
  234           long oFlushedPos = flushedPos;
  235           super.flushBefore(pos); // this will call checkClosed() for us
  236   
  237           long flushBytes = flushedPos - oFlushedPos;
  238           if (flushBytes > 0) {
  239               int bufLen = 512;
  240               byte[] buf = new byte[bufLen];
  241               cache.seek(oFlushedPos);
  242               while (flushBytes > 0) {
  243                   int len = (int)Math.min(flushBytes, bufLen);
  244                   cache.readFully(buf, 0, len);
  245                   stream.write(buf, 0, len);
  246                   flushBytes -= len;
  247               }
  248               stream.flush();
  249           }
  250       }
  251   }

Save This Page
Home » openjdk-7 » javax » imageio » stream » [javadoc | source]