Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageOutputStream.java
41153 views
1
/*
2
* Copyright (c) 2000, 2012, 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 java.nio.file.Files;
33
import com.sun.imageio.stream.StreamCloser;
34
35
/**
36
* An implementation of {@code ImageOutputStream} that writes its
37
* output to a regular {@code OutputStream}. A file is used to
38
* cache data until it is flushed to the output stream.
39
*
40
*/
41
public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
42
43
private OutputStream stream;
44
45
private File cacheFile;
46
47
private RandomAccessFile cache;
48
49
// Pos after last (rightmost) byte written
50
private long maxStreamPos = 0L;
51
52
/** The CloseAction that closes the stream in
53
* the StreamCloser's shutdown hook */
54
private final StreamCloser.CloseAction closeAction;
55
56
/**
57
* Constructs a {@code FileCacheImageOutputStream} that will write
58
* to a given {@code outputStream}.
59
*
60
* <p> A temporary file is used as a cache. If
61
* {@code cacheDir} is non-{@code null} and is a
62
* directory, the file will be created there. If it is
63
* {@code null}, the system-dependent default temporary-file
64
* directory will be used (see the documentation for
65
* {@code File.createTempFile} for details).
66
*
67
* @param stream an {@code OutputStream} to write to.
68
* @param cacheDir a {@code File} indicating where the
69
* cache file should be created, or {@code null} to use the
70
* system directory.
71
*
72
* @exception IllegalArgumentException if {@code stream}
73
* is {@code null}.
74
* @exception IllegalArgumentException if {@code cacheDir} is
75
* non-{@code null} but is not a directory.
76
* @exception IOException if a cache file cannot be created.
77
*/
78
public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
79
throws IOException {
80
if (stream == null) {
81
throw new IllegalArgumentException("stream == null!");
82
}
83
if ((cacheDir != null) && !(cacheDir.isDirectory())) {
84
throw new IllegalArgumentException("Not a directory!");
85
}
86
this.stream = stream;
87
if (cacheDir == null)
88
this.cacheFile = Files.createTempFile("imageio", ".tmp").toFile();
89
else
90
this.cacheFile = Files.createTempFile(cacheDir.toPath(), "imageio", ".tmp")
91
.toFile();
92
this.cache = new RandomAccessFile(cacheFile, "rw");
93
94
this.closeAction = StreamCloser.createCloseAction(this);
95
StreamCloser.addToQueue(closeAction);
96
}
97
98
public int read() throws IOException {
99
checkClosed();
100
bitOffset = 0;
101
int val = cache.read();
102
if (val != -1) {
103
++streamPos;
104
}
105
return val;
106
}
107
108
public int read(byte[] b, int off, int len) throws IOException {
109
checkClosed();
110
111
if (b == null) {
112
throw new NullPointerException("b == null!");
113
}
114
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
115
throw new IndexOutOfBoundsException
116
("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
117
}
118
119
bitOffset = 0;
120
121
if (len == 0) {
122
return 0;
123
}
124
125
int nbytes = cache.read(b, off, len);
126
if (nbytes != -1) {
127
streamPos += nbytes;
128
}
129
return nbytes;
130
}
131
132
public void write(int b) throws IOException {
133
flushBits(); // this will call checkClosed() for us
134
cache.write(b);
135
++streamPos;
136
maxStreamPos = Math.max(maxStreamPos, streamPos);
137
}
138
139
public void write(byte[] b, int off, int len) throws IOException {
140
flushBits(); // this will call checkClosed() for us
141
cache.write(b, off, len);
142
streamPos += len;
143
maxStreamPos = Math.max(maxStreamPos, streamPos);
144
}
145
146
public long length() {
147
try {
148
checkClosed();
149
return cache.length();
150
} catch (IOException e) {
151
return -1L;
152
}
153
}
154
155
/**
156
* Sets the current stream position and resets the bit offset to
157
* 0. It is legal to seek past the end of the file; an
158
* {@code EOFException} will be thrown only if a read is
159
* performed. The file length will not be increased until a write
160
* is performed.
161
*
162
* @exception IndexOutOfBoundsException if {@code pos} is smaller
163
* than the flushed position.
164
* @exception IOException if any other I/O error occurs.
165
*/
166
public void seek(long pos) throws IOException {
167
checkClosed();
168
169
if (pos < flushedPos) {
170
throw new IndexOutOfBoundsException();
171
}
172
173
cache.seek(pos);
174
this.streamPos = cache.getFilePointer();
175
maxStreamPos = Math.max(maxStreamPos, streamPos);
176
this.bitOffset = 0;
177
}
178
179
/**
180
* Returns {@code true} since this
181
* {@code ImageOutputStream} caches data in order to allow
182
* seeking backwards.
183
*
184
* @return {@code true}.
185
*
186
* @see #isCachedMemory
187
* @see #isCachedFile
188
*/
189
public boolean isCached() {
190
return true;
191
}
192
193
/**
194
* Returns {@code true} since this
195
* {@code ImageOutputStream} maintains a file cache.
196
*
197
* @return {@code true}.
198
*
199
* @see #isCached
200
* @see #isCachedMemory
201
*/
202
public boolean isCachedFile() {
203
return true;
204
}
205
206
/**
207
* Returns {@code false} since this
208
* {@code ImageOutputStream} does not maintain a main memory
209
* cache.
210
*
211
* @return {@code false}.
212
*
213
* @see #isCached
214
* @see #isCachedFile
215
*/
216
public boolean isCachedMemory() {
217
return false;
218
}
219
220
/**
221
* Closes this {@code FileCacheImageOutputStream}. All
222
* pending data is flushed to the output, and the cache file
223
* is closed and removed. The destination {@code OutputStream}
224
* is not closed.
225
*
226
* @exception IOException if an error occurs.
227
*/
228
public void close() throws IOException {
229
maxStreamPos = cache.length();
230
231
seek(maxStreamPos);
232
flushBefore(maxStreamPos);
233
super.close();
234
cache.close();
235
cache = null;
236
cacheFile.delete();
237
cacheFile = null;
238
stream.flush();
239
stream = null;
240
StreamCloser.removeFromQueue(closeAction);
241
}
242
243
public void flushBefore(long pos) throws IOException {
244
long oFlushedPos = flushedPos;
245
super.flushBefore(pos); // this will call checkClosed() for us
246
247
long flushBytes = flushedPos - oFlushedPos;
248
if (flushBytes > 0) {
249
int bufLen = 512;
250
byte[] buf = new byte[bufLen];
251
cache.seek(oFlushedPos);
252
while (flushBytes > 0) {
253
int len = (int)Math.min(flushBytes, bufLen);
254
cache.readFully(buf, 0, len);
255
stream.write(buf, 0, len);
256
flushBytes -= len;
257
}
258
stream.flush();
259
}
260
}
261
}
262
263