blob: ae485854b3d849b48a21a195e4a3db332f054797 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19package javax.imageio.stream;
20
21import java.io.IOException;
22import java.io.File;
23import java.io.OutputStream;
24import java.io.RandomAccessFile;
25
26/**
27 * The FileCacheImageOutputStream class is an implementation of
28 * ImageOutputStream that writes to its OutputStream
29 * using a temporary file as a cache.
30 */
31public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
32
33 /** The Constant IIO_TEMP_FILE_PREFIX. */
34 static final String IIO_TEMP_FILE_PREFIX = "iioCache";
35
36 /** The Constant MAX_BUFFER_LEN. */
37 static final int MAX_BUFFER_LEN = 1048575; // 1 MB - is it not too much?
38
39 /** The os. */
40 private OutputStream os;
41
42 /** The file. */
43 private File file;
44
45 /** The raf. */
46 private RandomAccessFile raf;
47
48 /**
49 * Instantiates a FileCacheImageOutputStream.
50 *
51 * @param stream the OutputStream for writing.
52 * @param cacheDir the cache directory where the chache file
53 * will be created.
54 *
55 * @throws IOException Signals that an I/O exception has occurred.
56 */
57 public FileCacheImageOutputStream(OutputStream stream, File cacheDir) throws IOException {
58 if (stream == null) {
59 throw new IllegalArgumentException("stream == null!");
60 }
61 os = stream;
62
63 if (cacheDir == null || cacheDir.isDirectory()) {
64 file = File.createTempFile(IIO_TEMP_FILE_PREFIX, null, cacheDir);
65 file.deleteOnExit();
66 } else {
67 throw new IllegalArgumentException("Not a directory!");
68 }
69
70 raf = new RandomAccessFile(file, "rw");
71 }
72
73 @Override
74 public void close() throws IOException {
75 flushBefore(raf.length());
76 super.close();
77 raf.close();
78 file.delete();
79 }
80
81 @Override
82 public boolean isCached() {
83 return true;
84 }
85
86 @Override
87 public boolean isCachedFile() {
88 return true;
89 }
90
91 @Override
92 public boolean isCachedMemory() {
93 return false;
94 }
95
96 @Override
97 public void write(int b) throws IOException {
98 flushBits(); // See the flushBits method description
99
100 raf.write(b);
101 streamPos++;
102 }
103
104 @Override
105 public void write(byte[] b, int off, int len) throws IOException {
106 flushBits(); // See the flushBits method description
107
108 raf.write(b, off, len);
109 streamPos += len;
110 }
111
112 @Override
113 public int read() throws IOException {
114 bitOffset = 0; // Should reset
115
116 int res = raf.read();
117 if (res >= 0) {
118 streamPos++;
119 }
120
121 return res;
122 }
123
124 @Override
125 public int read(byte[] b, int off, int len) throws IOException {
126 bitOffset = 0;
127
128 int numRead = raf.read(b, off, len);
129 if (numRead > 0) {
130 streamPos += numRead;
131 }
132
133 return numRead;
134 }
135
136 @Override
137 public void flushBefore(long pos) throws IOException {
138 long readFromPos = flushedPos;
139 super.flushBefore(pos);
140
141 long bytesToRead = pos - readFromPos;
142 raf.seek(readFromPos);
143
144 if (bytesToRead < MAX_BUFFER_LEN) {
145 byte buffer[] = new byte[(int)bytesToRead];
146 raf.readFully(buffer);
147 os.write(buffer);
148 } else {
149 byte buffer[] = new byte[MAX_BUFFER_LEN];
150 while (bytesToRead > 0) {
151 int count = (int) Math.min(MAX_BUFFER_LEN, bytesToRead);
152 raf.readFully(buffer, 0, count);
153 os.write(buffer, 0, count);
154 bytesToRead -= count;
155 }
156 }
157
158 os.flush();
159
160 if (pos != streamPos) {
161 raf.seek(streamPos); // Reset the position
162 }
163 }
164
165 @Override
166 public void seek(long pos) throws IOException {
167 if (pos < flushedPos) {
168 throw new IndexOutOfBoundsException();
169 }
170
171 raf.seek(pos);
172 streamPos = raf.getFilePointer();
173 bitOffset = 0;
174 }
175
176 @Override
177 public long length() {
178 try {
179 return raf.length();
180 } catch(IOException e) {
181 return -1L;
182 }
183 }
184}