History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/imageio/stream/FileCacheImageOutputStream.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/imageio/stream/FileCacheImageOutputStream.java+257−0
@@ -0,0 +1,257 @@
1/*
2 * Copyright (c) 2000, 2007, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.imageio.stream;
27
28import java.io.File;
29import java.io.IOException;
30import java.io.OutputStream;
31import java.io.RandomAccessFile;
32import 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 */
40public 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 /** The CloseAction that closes the stream in
52 * the StreamCloser's shutdown hook */
53 private final StreamCloser.CloseAction closeAction;
54
55 /**
56 * Constructs a <code>FileCacheImageOutputStream</code> that will write
57 * to a given <code>outputStream</code>.
58 *
59 * <p> A temporary file is used as a cache. If
60 * <code>cacheDir</code>is non-<code>null</code> and is a
61 * directory, the file will be created there. If it is
62 * <code>null</code>, the system-dependent default temporary-file
63 * directory will be used (see the documentation for
64 * <code>File.createTempFile</code> for details).
65 *
66 * @param stream an <code>OutputStream</code> to write to.
67 * @param cacheDir a <code>File</code> indicating where the
68 * cache file should be created, or <code>null</code> to use the
69 * system directory.
70 *
71 * @exception IllegalArgumentException if <code>stream</code>
72 * is <code>null</code>.
73 * @exception IllegalArgumentException if <code>cacheDir</code> is
74 * non-<code>null</code> but is not a directory.
75 * @exception IOException if a cache file cannot be created.
76 */
77 public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
78 throws IOException {
79 if (stream == null) {
80 throw new IllegalArgumentException("stream == null!");
81 }
82 if ((cacheDir != null) && !(cacheDir.isDirectory())) {
83 throw new IllegalArgumentException("Not a directory!");
84 }
85 this.stream = stream;
86 this.cacheFile =
87 File.createTempFile("imageio", ".tmp", cacheDir);
88 this.cache = new RandomAccessFile(cacheFile, "rw");
89
90 this.closeAction = StreamCloser.createCloseAction(this);
91 StreamCloser.addToQueue(closeAction);
92 }
93
94 public int read() throws IOException {
95 checkClosed();
96 bitOffset = 0;
97 int val = cache.read();
98 if (val != -1) {
99 ++streamPos;
100 }
101 return val;
102 }
103
104 public int read(byte[] b, int off, int len) throws IOException {
105 checkClosed();
106
107 if (b == null) {
108 throw new NullPointerException("b == null!");
109 }
110 if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
111 throw new IndexOutOfBoundsException
112 ("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
113 }
114
115 bitOffset = 0;
116
117 if (len == 0) {
118 return 0;
119 }
120
121 int nbytes = cache.read(b, off, len);
122 if (nbytes != -1) {
123 streamPos += nbytes;
124 }
125 return nbytes;
126 }
127
128 public void write(int b) throws IOException {
129 flushBits(); // this will call checkClosed() for us
130 cache.write(b);
131 ++streamPos;
132 maxStreamPos = Math.max(maxStreamPos, streamPos);
133 }
134
135 public void write(byte[] b, int off, int len) throws IOException {
136 flushBits(); // this will call checkClosed() for us
137 cache.write(b, off, len);
138 streamPos += len;
139 maxStreamPos = Math.max(maxStreamPos, streamPos);
140 }
141
142 public long length() {
143 try {
144 checkClosed();
145 return cache.length();
146 } catch (IOException e) {
147 return -1L;
148 }
149 }
150
151 /**
152 * Sets the current stream position and resets the bit offset to
153 * 0. It is legal to seek past the end of the file; an
154 * <code>EOFException</code> will be thrown only if a read is
155 * performed. The file length will not be increased until a write
156 * is performed.
157 *
158 * @exception IndexOutOfBoundsException if <code>pos</code> is smaller
159 * than the flushed position.
160 * @exception IOException if any other I/O error occurs.
161 */
162 public void seek(long pos) throws IOException {
163 checkClosed();
164
165 if (pos < flushedPos) {
166 throw new IndexOutOfBoundsException();
167 }
168
169 cache.seek(pos);
170 this.streamPos = cache.getFilePointer();
171 maxStreamPos = Math.max(maxStreamPos, streamPos);
172 this.bitOffset = 0;
173 }
174
175 /**
176 * Returns <code>true</code> since this
177 * <code>ImageOutputStream</code> caches data in order to allow
178 * seeking backwards.
179 *
180 * @return <code>true</code>.
181 *
182 * @see #isCachedMemory
183 * @see #isCachedFile
184 */
185 public boolean isCached() {
186 return true;
187 }
188
189 /**
190 * Returns <code>true</code> since this
191 * <code>ImageOutputStream</code> maintains a file cache.
192 *
193 * @return <code>true</code>.
194 *
195 * @see #isCached
196 * @see #isCachedMemory
197 */
198 public boolean isCachedFile() {
199 return true;
200 }
201
202 /**
203 * Returns <code>false</code> since this
204 * <code>ImageOutputStream</code> does not maintain a main memory
205 * cache.
206 *
207 * @return <code>false</code>.
208 *
209 * @see #isCached
210 * @see #isCachedFile
211 */
212 public boolean isCachedMemory() {
213 return false;
214 }
215
216 /**
217 * Closes this <code>FileCacheImageOutputStream</code>. All
218 * pending data is flushed to the output, and the cache file
219 * is closed and removed. The destination <code>OutputStream</code>
220 * is not closed.
221 *
222 * @exception IOException if an error occurs.
223 */
224 public void close() throws IOException {
225 maxStreamPos = cache.length();
226
227 seek(maxStreamPos);
228 flushBefore(maxStreamPos);
229 super.close();
230 cache.close();
231 cache = null;
232 cacheFile.delete();
233 cacheFile = null;
234 stream.flush();
235 stream = null;
236 StreamCloser.removeFromQueue(closeAction);
237 }
238
239 public void flushBefore(long pos) throws IOException {
240 long oFlushedPos = flushedPos;
241 super.flushBefore(pos); // this will call checkClosed() for us
242
243 long flushBytes = flushedPos - oFlushedPos;
244 if (flushBytes > 0) {
245 int bufLen = 512;
246 byte[] buf = new byte[bufLen];
247 cache.seek(oFlushedPos);
248 while (flushBytes > 0) {
249 int len = (int)Math.min(flushBytes, bufLen);
250 cache.readFully(buf, 0, len);
251 stream.write(buf, 0, len);
252 flushBytes -= len;
253 }
254 stream.flush();
255 }
256 }
257}