Path: blob/master/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageOutputStream.java
41153 views
/*1* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.imageio.stream;2627import java.io.IOException;28import java.io.OutputStream;2930/**31* An implementation of {@code ImageOutputStream} that writes its32* output to a regular {@code OutputStream}. A memory buffer is33* used to cache at least the data between the discard position and34* the current write position. The only constructor takes an35* {@code OutputStream}, so this class may not be used for36* read/modify/write operations. Reading can occur only on parts of37* the stream that have already been written to the cache and not38* yet flushed.39*40*/41public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl {4243private OutputStream stream;4445private MemoryCache cache = new MemoryCache();4647/**48* Constructs a {@code MemoryCacheImageOutputStream} that will write49* to a given {@code OutputStream}.50*51* @param stream an {@code OutputStream} to write to.52*53* @exception IllegalArgumentException if {@code stream} is54* {@code null}.55*/56public MemoryCacheImageOutputStream(OutputStream stream) {57if (stream == null) {58throw new IllegalArgumentException("stream == null!");59}60this.stream = stream;61}6263public int read() throws IOException {64checkClosed();6566bitOffset = 0;6768int val = cache.read(streamPos);69if (val != -1) {70++streamPos;71}72return val;73}7475public int read(byte[] b, int off, int len) throws IOException {76checkClosed();7778if (b == null) {79throw new NullPointerException("b == null!");80}81// Fix 4467608: read([B,I,I) works incorrectly if len<=082if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {83throw new IndexOutOfBoundsException84("off < 0 || len < 0 || off+len > b.length || off+len < 0!");85}8687bitOffset = 0;8889if (len == 0) {90return 0;91}9293// check if we're already at/past EOF i.e.94// no more bytes left to read from cache95long bytesLeftInCache = cache.getLength() - streamPos;96if (bytesLeftInCache <= 0) {97return -1; // EOF98}99100// guaranteed by now that bytesLeftInCache > 0 && len > 0101// and so the rest of the error checking is done by cache.read()102// NOTE that alot of error checking is duplicated103len = (int)Math.min(bytesLeftInCache, (long)len);104cache.read(b, off, len, streamPos);105streamPos += len;106return len;107}108109public void write(int b) throws IOException {110flushBits(); // this will call checkClosed() for us111cache.write(b, streamPos);112++streamPos;113}114115public void write(byte[] b, int off, int len) throws IOException {116flushBits(); // this will call checkClosed() for us117cache.write(b, off, len, streamPos);118streamPos += len;119}120121public long length() {122try {123checkClosed();124return cache.getLength();125} catch (IOException e) {126return -1L;127}128}129130/**131* Returns {@code true} since this132* {@code ImageOutputStream} caches data in order to allow133* seeking backwards.134*135* @return {@code true}.136*137* @see #isCachedMemory138* @see #isCachedFile139*/140public boolean isCached() {141return true;142}143144/**145* Returns {@code false} since this146* {@code ImageOutputStream} does not maintain a file cache.147*148* @return {@code false}.149*150* @see #isCached151* @see #isCachedMemory152*/153public boolean isCachedFile() {154return false;155}156157/**158* Returns {@code true} since this159* {@code ImageOutputStream} maintains a main memory cache.160*161* @return {@code true}.162*163* @see #isCached164* @see #isCachedFile165*/166public boolean isCachedMemory() {167return true;168}169170/**171* Closes this {@code MemoryCacheImageOutputStream}. All172* pending data is flushed to the output, and the cache173* is released. The destination {@code OutputStream}174* is not closed.175*/176public void close() throws IOException {177long length = cache.getLength();178seek(length);179flushBefore(length);180super.close();181cache.reset();182cache = null;183stream = null;184}185186public void flushBefore(long pos) throws IOException {187long oFlushedPos = flushedPos;188super.flushBefore(pos); // this will call checkClosed() for us189190long flushBytes = flushedPos - oFlushedPos;191cache.writeToStream(stream, oFlushedPos, flushBytes);192cache.disposeBefore(flushedPos);193stream.flush();194}195}196197198