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+
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+ /** 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+}