blob: 768d9783e4e103c7c71f44e28d0f54593f414a40 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1995-2003 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 sun.awt.image;
27
28import java.awt.image.*;
29import java.io.InputStream;
30import java.io.IOException;
31import java.io.BufferedInputStream;
32import java.util.Hashtable;
33
34public abstract class InputStreamImageSource implements ImageProducer,
35 ImageFetchable
36{
37 ImageConsumerQueue consumers;
38
39 ImageDecoder decoder;
40 ImageDecoder decoders;
41
42 boolean awaitingFetch = false;
43
44 abstract boolean checkSecurity(Object context, boolean quiet);
45
46 int countConsumers(ImageConsumerQueue cq) {
47 int i = 0;
48 while (cq != null) {
49 i++;
50 cq = cq.next;
51 }
52 return i;
53 }
54
55 synchronized int countConsumers() {
56 ImageDecoder id = decoders;
57 int i = countConsumers(consumers);
58 while (id != null) {
59 i += countConsumers(id.queue);
60 id = id.next;
61 }
62 return i;
63 }
64
65 public void addConsumer(ImageConsumer ic) {
66 addConsumer(ic, false);
67 }
68
69 synchronized void printQueue(ImageConsumerQueue cq, String prefix) {
70 while (cq != null) {
71 System.out.println(prefix+cq);
72 cq = cq.next;
73 }
74 }
75
76 synchronized void printQueues(String title) {
77 System.out.println(title+"[ -----------");
78 printQueue(consumers, " ");
79 for (ImageDecoder id = decoders; id != null; id = id.next) {
80 System.out.println(" "+id);
81 printQueue(id.queue, " ");
82 }
83 System.out.println("----------- ]"+title);
84 }
85
86 synchronized void addConsumer(ImageConsumer ic, boolean produce) {
87 checkSecurity(null, false);
88 for (ImageDecoder id = decoders; id != null; id = id.next) {
89 if (id.isConsumer(ic)) {
90 // This consumer is already being fed.
91 return;
92 }
93 }
94 ImageConsumerQueue cq = consumers;
95 while (cq != null && cq.consumer != ic) {
96 cq = cq.next;
97 }
98 if (cq == null) {
99 cq = new ImageConsumerQueue(this, ic);
100 cq.next = consumers;
101 consumers = cq;
102 } else {
103 if (!cq.secure) {
104 Object context = null;
105 SecurityManager security = System.getSecurityManager();
106 if (security != null) {
107 context = security.getSecurityContext();
108 }
109 if (cq.securityContext == null) {
110 cq.securityContext = context;
111 } else if (!cq.securityContext.equals(context)) {
112 // If there are two different security contexts that both
113 // have a handle on the same ImageConsumer, then there has
114 // been a security breach and whether or not they trade
115 // image data is small fish compared to what they could be
116 // trading. Throw a Security exception anyway...
117 errorConsumer(cq, false);
118 throw new SecurityException("Applets are trading image data!");
119 }
120 }
121 cq.interested = true;
122 }
123 if (produce && decoder == null) {
124 startProduction();
125 }
126 }
127
128 public synchronized boolean isConsumer(ImageConsumer ic) {
129 for (ImageDecoder id = decoders; id != null; id = id.next) {
130 if (id.isConsumer(ic)) {
131 return true;
132 }
133 }
134 return ImageConsumerQueue.isConsumer(consumers, ic);
135 }
136
137 private void errorAllConsumers(ImageConsumerQueue cq, boolean needReload) {
138 while (cq != null) {
139 if (cq.interested) {
140 errorConsumer(cq, needReload);
141 }
142 cq = cq.next;
143 }
144 }
145
146 private void errorConsumer(ImageConsumerQueue cq, boolean needReload) {
147 cq.consumer.imageComplete(ImageConsumer.IMAGEERROR);
148 if ( needReload && cq.consumer instanceof ImageRepresentation) {
149 ((ImageRepresentation)cq.consumer).image.flush();
150 }
151 removeConsumer(cq.consumer);
152 }
153
154 public synchronized void removeConsumer(ImageConsumer ic) {
155 for (ImageDecoder id = decoders; id != null; id = id.next) {
156 id.removeConsumer(ic);
157 }
158 consumers = ImageConsumerQueue.removeConsumer(consumers, ic, false);
159 }
160
161 public void startProduction(ImageConsumer ic) {
162 addConsumer(ic, true);
163 }
164
165 private synchronized void startProduction() {
166 if (!awaitingFetch) {
167 ImageFetcher.add(this);
168 awaitingFetch = true;
169 }
170 }
171
172 private synchronized void stopProduction() {
173 if (awaitingFetch) {
174 ImageFetcher.remove(this);
175 awaitingFetch = false;
176 }
177 }
178
179 public void requestTopDownLeftRightResend(ImageConsumer ic) {
180 }
181
182 protected abstract ImageDecoder getDecoder();
183
184 protected ImageDecoder decoderForType(InputStream is,
185 String content_type) {
186 // Don't believe the content type - file extensions can
187 // lie.
188 /*
189 if (content_type.equals("image/gif")) {
190 return new GifImageDecoder(this, is);
191 } else if (content_type.equals("image/jpeg")) {
192 return new JPEGImageDecoder(this, is);
193 } else if (content_type.equals("image/x-xbitmap")) {
194 return new XbmImageDecoder(this, is);
195 }
196 else if (content_type == URL.content_jpeg) {
197 return new JpegImageDecoder(this, is);
198 } else if (content_type == URL.content_xbitmap) {
199 return new XbmImageDecoder(this, is);
200 } else if (content_type == URL.content_xpixmap) {
201 return new Xpm2ImageDecoder(this, is);
202 }
203 */
204
205 return null;
206 }
207
208 protected ImageDecoder getDecoder(InputStream is) {
209 if (!is.markSupported())
210 is = new BufferedInputStream(is);
211 try {
212 /* changed to support png
213 is.mark(6);
214 */
215 is.mark(8);
216 int c1 = is.read();
217 int c2 = is.read();
218 int c3 = is.read();
219 int c4 = is.read();
220 int c5 = is.read();
221 int c6 = is.read();
222 // added to support png
223 int c7 = is.read();
224 int c8 = is.read();
225 // end of adding
226 is.reset();
227 is.mark(-1);
228
229 if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
230 return new GifImageDecoder(this, is);
231 } else if (c1 == '\377' && c2 == '\330' && c3 == '\377') {
232 return new JPEGImageDecoder(this, is);
233 } else if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
234 return new XbmImageDecoder(this, is);
235// } else if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
236// c5 == 'M' && c6 == '2') {
237// return new Xpm2ImageDecoder(this, is);
238 // added to support png
239 } else if (c1 == 137 && c2 == 80 && c3 == 78 &&
240 c4 == 71 && c5 == 13 && c6 == 10 &&
241 c7 == 26 && c8 == 10) {
242 return new PNGImageDecoder(this, is);
243 }
244 // end of adding
245 } catch (IOException e) {
246 }
247
248 return null;
249 }
250
251 public void doFetch() {
252 synchronized (this) {
253 if (consumers == null) {
254 awaitingFetch = false;
255 return;
256 }
257 }
258 ImageDecoder imgd = getDecoder();
259 if (imgd == null) {
260 badDecoder();
261 } else {
262 setDecoder(imgd);
263 try {
264 imgd.produceImage();
265 } catch (IOException e) {
266 e.printStackTrace();
267 // the finally clause will send an error.
268 } catch (ImageFormatException e) {
269 e.printStackTrace();
270 // the finally clause will send an error.
271 } finally {
272 removeDecoder(imgd);
273 if ( Thread.currentThread().isInterrupted() || !Thread.currentThread().isAlive()) {
274 errorAllConsumers(imgd.queue, true);
275 } else {
276 errorAllConsumers(imgd.queue, false);
277 }
278 }
279 }
280 }
281
282 private void badDecoder() {
283 ImageConsumerQueue cq;
284 synchronized (this) {
285 cq = consumers;
286 consumers = null;
287 awaitingFetch = false;
288 }
289 errorAllConsumers(cq, false);
290 }
291
292 private void setDecoder(ImageDecoder mydecoder) {
293 ImageConsumerQueue cq;
294 synchronized (this) {
295 mydecoder.next = decoders;
296 decoders = mydecoder;
297 decoder = mydecoder;
298 cq = consumers;
299 mydecoder.queue = cq;
300 consumers = null;
301 awaitingFetch = false;
302 }
303 while (cq != null) {
304 if (cq.interested) {
305 // Now that there is a decoder, security may have changed
306 // so reverify it here, just in case.
307 if (!checkSecurity(cq.securityContext, true)) {
308 errorConsumer(cq, false);
309 }
310 }
311 cq = cq.next;
312 }
313 }
314
315 private synchronized void removeDecoder(ImageDecoder mydecoder) {
316 doneDecoding(mydecoder);
317 ImageDecoder idprev = null;
318 for (ImageDecoder id = decoders; id != null; id = id.next) {
319 if (id == mydecoder) {
320 if (idprev == null) {
321 decoders = id.next;
322 } else {
323 idprev.next = id.next;
324 }
325 break;
326 }
327 idprev = id;
328 }
329 }
330
331 synchronized void doneDecoding(ImageDecoder mydecoder) {
332 if (decoder == mydecoder) {
333 decoder = null;
334 if (consumers != null) {
335 startProduction();
336 }
337 }
338 }
339
340 void latchConsumers(ImageDecoder id) {
341 doneDecoding(id);
342 }
343
344 synchronized void flush() {
345 decoder = null;
346 }
347}