blob: cdf41841dae1419fbd6d8ea5880fdc253b1f4156 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 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
26package javax.imageio.stream;
27
28import java.io.IOException;
29import java.io.OutputStream;
30
31/**
32 * An implementation of <code>ImageOutputStream</code> that writes its
33 * output to a regular <code>OutputStream</code>. A memory buffer is
34 * used to cache at least the data between the discard position and
35 * the current write position. The only constructor takes an
36 * <code>OutputStream</code>, so this class may not be used for
37 * read/modify/write operations. Reading can occur only on parts of
38 * the stream that have already been written to the cache and not
39 * yet flushed.
40 *
41 */
42public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl {
43
44 private OutputStream stream;
45
46 private MemoryCache cache = new MemoryCache();
47
48 /**
49 * Constructs a <code>MemoryCacheImageOutputStream</code> that will write
50 * to a given <code>OutputStream</code>.
51 *
52 * @param stream an <code>OutputStream</code> to write to.
53 *
54 * @exception IllegalArgumentException if <code>stream</code> is
55 * <code>null</code>.
56 */
57 public MemoryCacheImageOutputStream(OutputStream stream) {
58 if (stream == null) {
59 throw new IllegalArgumentException("stream == null!");
60 }
61 this.stream = stream;
62 }
63
64 public int read() throws IOException {
65 checkClosed();
66
67 bitOffset = 0;
68
69 int val = cache.read(streamPos);
70 if (val != -1) {
71 ++streamPos;
72 }
73 return val;
74 }
75
76 public int read(byte[] b, int off, int len) throws IOException {
77 checkClosed();
78
79 if (b == null) {
80 throw new NullPointerException("b == null!");
81 }
82 // Fix 4467608: read([B,I,I) works incorrectly if len<=0
83 if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
84 throw new IndexOutOfBoundsException
85 ("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
86 }
87
88 bitOffset = 0;
89
90 if (len == 0) {
91 return 0;
92 }
93
94 // check if we're already at/past EOF i.e.
95 // no more bytes left to read from cache
96 long bytesLeftInCache = cache.getLength() - streamPos;
97 if (bytesLeftInCache <= 0) {
98 return -1; // EOF
99 }
100
101 // guaranteed by now that bytesLeftInCache > 0 && len > 0
102 // and so the rest of the error checking is done by cache.read()
103 // NOTE that alot of error checking is duplicated
104 len = (int)Math.min(bytesLeftInCache, (long)len);
105 cache.read(b, off, len, streamPos);
106 streamPos += len;
107 return len;
108 }
109
110 public void write(int b) throws IOException {
111 flushBits(); // this will call checkClosed() for us
112 cache.write(b, streamPos);
113 ++streamPos;
114 }
115
116 public void write(byte[] b, int off, int len) throws IOException {
117 flushBits(); // this will call checkClosed() for us
118 cache.write(b, off, len, streamPos);
119 streamPos += len;
120 }
121
122 public long length() {
123 try {
124 checkClosed();
125 return cache.getLength();
126 } catch (IOException e) {
127 return -1L;
128 }
129 }
130
131 /**
132 * Returns <code>true</code> since this
133 * <code>ImageOutputStream</code> caches data in order to allow
134 * seeking backwards.
135 *
136 * @return <code>true</code>.
137 *
138 * @see #isCachedMemory
139 * @see #isCachedFile
140 */
141 public boolean isCached() {
142 return true;
143 }
144
145 /**
146 * Returns <code>false</code> since this
147 * <code>ImageOutputStream</code> does not maintain a file cache.
148 *
149 * @return <code>false</code>.
150 *
151 * @see #isCached
152 * @see #isCachedMemory
153 */
154 public boolean isCachedFile() {
155 return false;
156 }
157
158 /**
159 * Returns <code>true</code> since this
160 * <code>ImageOutputStream</code> maintains a main memory cache.
161 *
162 * @return <code>true</code>.
163 *
164 * @see #isCached
165 * @see #isCachedFile
166 */
167 public boolean isCachedMemory() {
168 return true;
169 }
170
171 /**
172 * Closes this <code>MemoryCacheImageOutputStream</code>. All
173 * pending data is flushed to the output, and the cache
174 * is released. The destination <code>OutputStream</code>
175 * is not closed.
176 */
177 public void close() throws IOException {
178 long length = cache.getLength();
179 seek(length);
180 flushBefore(length);
181 super.close();
182 cache.reset();
183 cache = null;
184 stream = null;
185 }
186
187 public void flushBefore(long pos) throws IOException {
188 long oFlushedPos = flushedPos;
189 super.flushBefore(pos); // this will call checkClosed() for us
190
191 long flushBytes = flushedPos - oFlushedPos;
192 cache.writeToStream(stream, oFlushedPos, flushBytes);
193 cache.disposeBefore(flushedPos);
194 stream.flush();
195 }
196}