001: /*
002: * @(#)InputStreamImageSource.java 1.56 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.awt.image;
029:
030: import java.awt.image.*;
031: import java.io.InputStream;
032: import java.io.IOException;
033: import java.io.BufferedInputStream;
034: import java.util.Hashtable;
035:
036: public abstract class InputStreamImageSource implements ImageProducer,
037: ImageFetchable {
038: ImageConsumerQueue consumers;
039:
040: ImageDecoder decoder;
041: ImageDecoder decoders;
042:
043: boolean awaitingFetch = false;
044:
045: abstract boolean checkSecurity(Object context, boolean quiet);
046:
047: int countConsumers(ImageConsumerQueue cq) {
048: int i = 0;
049: while (cq != null) {
050: i++;
051: cq = cq.next;
052: }
053: return i;
054: }
055:
056: synchronized int countConsumers() {
057: ImageDecoder id = decoders;
058: int i = countConsumers(consumers);
059: while (id != null) {
060: i += countConsumers(id.queue);
061: id = id.next;
062: }
063: return i;
064: }
065:
066: public void addConsumer(ImageConsumer ic) {
067: addConsumer(ic, false);
068: }
069:
070: synchronized void printQueue(ImageConsumerQueue cq, String prefix) {
071: while (cq != null) {
072: System.out.println(prefix + cq);
073: cq = cq.next;
074: }
075: }
076:
077: synchronized void printQueues(String title) {
078: System.out.println(title + "[ -----------");
079: printQueue(consumers, " ");
080: for (ImageDecoder id = decoders; id != null; id = id.next) {
081: System.out.println(" " + id);
082: printQueue(id.queue, " ");
083: }
084: System.out.println("----------- ]" + title);
085: }
086:
087: synchronized void addConsumer(ImageConsumer ic, boolean produce) {
088: checkSecurity(null, false);
089: for (ImageDecoder id = decoders; id != null; id = id.next) {
090: if (id.isConsumer(ic)) {
091: // This consumer is already being fed.
092: return;
093: }
094: }
095: ImageConsumerQueue cq = consumers;
096: while (cq != null && cq.consumer != ic) {
097: cq = cq.next;
098: }
099: if (cq == null) {
100: cq = new ImageConsumerQueue(this , ic);
101: cq.next = consumers;
102: consumers = cq;
103: } else {
104: if (!cq.secure) {
105: Object context = null;
106: SecurityManager security = System.getSecurityManager();
107: if (security != null) {
108: context = security.getSecurityContext();
109: }
110: if (cq.securityContext == null) {
111: cq.securityContext = context;
112: } else if (!cq.securityContext.equals(context)) {
113: // If there are two different security contexts that both
114: // have a handle on the same ImageConsumer, then there has
115: // been a security breach and whether or not they trade
116: // image data is small fish compared to what they could be
117: // trading. Throw a Security exception anyway...
118: errorConsumer(cq, false);
119: throw new SecurityException(
120: "Applets are trading image data!");
121: }
122: }
123: cq.interested = true;
124: }
125: if (produce && decoder == null) {
126: startProduction();
127: }
128: }
129:
130: public synchronized boolean isConsumer(ImageConsumer ic) {
131: for (ImageDecoder id = decoders; id != null; id = id.next) {
132: if (id.isConsumer(ic)) {
133: return true;
134: }
135: }
136: return ImageConsumerQueue.isConsumer(consumers, ic);
137: }
138:
139: private void errorAllConsumers(ImageConsumerQueue cq,
140: boolean needReload) {
141: while (cq != null) {
142: if (cq.interested) {
143: errorConsumer(cq, needReload);
144: }
145: cq = cq.next;
146: }
147: }
148:
149: private void errorConsumer(ImageConsumerQueue cq, boolean needReload) {
150: cq.consumer.imageComplete(ImageConsumer.IMAGEERROR);
151: if (needReload && cq.consumer instanceof ImageRepresentation) {
152: ((ImageRepresentation) cq.consumer).image.flush();
153: }
154: removeConsumer(cq.consumer);
155: }
156:
157: public synchronized void removeConsumer(ImageConsumer ic) {
158: for (ImageDecoder id = decoders; id != null; id = id.next) {
159: id.removeConsumer(ic);
160: }
161: consumers = ImageConsumerQueue.removeConsumer(consumers, ic,
162: false);
163: }
164:
165: public void startProduction(ImageConsumer ic) {
166: addConsumer(ic, true);
167: }
168:
169: private synchronized void startProduction() {
170: if (!awaitingFetch) {
171: ImageFetcher.add(this );
172: awaitingFetch = true;
173: }
174: }
175:
176: private synchronized void stopProduction() {
177: if (awaitingFetch) {
178: ImageFetcher.remove(this );
179: awaitingFetch = false;
180: }
181: }
182:
183: public void requestTopDownLeftRightResend(ImageConsumer ic) {
184: }
185:
186: protected abstract ImageDecoder getDecoder();
187:
188: protected ImageDecoder decoderForType(InputStream is,
189: String content_type) {
190: // Don't believe the content type - file extensions can
191: // lie.
192: /*
193: if (content_type.equals("image/gif")) {
194: return new GifImageDecoder(this, is);
195: } else if (content_type.equals("image/jpeg")) {
196: return new JPEGImageDecoder(this, is);
197: } else if (content_type.equals("image/x-xbitmap")) {
198: return new XbmImageDecoder(this, is);
199: }
200: else if (content_type == URL.content_jpeg) {
201: return new JpegImageDecoder(this, is);
202: } else if (content_type == URL.content_xbitmap) {
203: return new XbmImageDecoder(this, is);
204: } else if (content_type == URL.content_xpixmap) {
205: return new Xpm2ImageDecoder(this, is);
206: }
207: */
208:
209: return null;
210: }
211:
212: protected ImageDecoder getDecoder(InputStream is) {
213: if (!is.markSupported())
214: is = new BufferedInputStream(is);
215: try {
216: is.mark(8);
217: int c1 = is.read();
218: int c2 = is.read();
219: int c3 = is.read();
220: int c4 = is.read();
221: int c5 = is.read();
222: int c6 = is.read();
223: int c7 = is.read();
224: int c8 = is.read();
225: is.reset();
226: is.mark(-1);
227:
228: ImageDecoderFactory factory = ImageDecoderFactory
229: .getInstance();
230: if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
231: return factory.newImageDecoder(this , is,
232: ImageDecoderFactory.IMG_FORMAT_GIF);
233: } else if (c1 == '\377' && c2 == '\330' && c3 == '\377') {
234: return factory.newImageDecoder(this , is,
235: ImageDecoderFactory.IMG_FORMAT_JPG);
236: } else if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
237: return factory.newImageDecoder(this , is,
238: ImageDecoderFactory.IMG_FORMAT_XBM);
239: // } else if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
240: // c5 == 'M' && c6 == '2') {
241: // return new Xpm2ImageDecoder(this, is);
242: } else if (c1 == 137 && c2 == 80 && c3 == 78 && c4 == 71
243: && c5 == 13 && c6 == 10 && c7 == 26 && c8 == 10) {
244: return factory.newImageDecoder(this , is,
245: ImageDecoderFactory.IMG_FORMAT_PNG);
246: }
247: } catch (IOException e) {
248: }
249: return null;
250: }
251:
252: public void doFetch() {
253: synchronized (this ) {
254: if (consumers == null) {
255: awaitingFetch = false;
256: return;
257: }
258: }
259: ImageDecoder imgd = getDecoder();
260: if (imgd == null) {
261: badDecoder();
262: } else {
263: setDecoder(imgd);
264: try {
265: imgd.produceImage();
266: } catch (IOException e) {
267: e.printStackTrace();
268: // the finally clause will send an error.
269: } catch (ImageFormatException e) {
270: e.printStackTrace();
271: // the finally clause will send an error.
272: } finally {
273: removeDecoder(imgd);
274: if (Thread.currentThread().isInterrupted()
275: || !Thread.currentThread().isAlive()) {
276: errorAllConsumers(imgd.queue, true);
277: } else {
278: errorAllConsumers(imgd.queue, false);
279: }
280: }
281: }
282: }
283:
284: private void badDecoder() {
285: ImageConsumerQueue cq;
286: synchronized (this ) {
287: cq = consumers;
288: consumers = null;
289: awaitingFetch = false;
290: }
291: errorAllConsumers(cq, false);
292: }
293:
294: private void setDecoder(ImageDecoder mydecoder) {
295: ImageConsumerQueue cq;
296: synchronized (this ) {
297: mydecoder.next = decoders;
298: decoders = mydecoder;
299: decoder = mydecoder;
300: cq = consumers;
301: mydecoder.queue = cq;
302: consumers = null;
303: awaitingFetch = false;
304: }
305: while (cq != null) {
306: if (cq.interested) {
307: // Now that there is a decoder, security may have changed
308: // so reverify it here, just in case.
309: if (!checkSecurity(cq.securityContext, true)) {
310: errorConsumer(cq, false);
311: }
312: }
313: cq = cq.next;
314: }
315: }
316:
317: private synchronized void removeDecoder(ImageDecoder mydecoder) {
318: doneDecoding(mydecoder);
319: ImageDecoder idprev = null;
320: for (ImageDecoder id = decoders; id != null; id = id.next) {
321: if (id == mydecoder) {
322: if (idprev == null) {
323: decoders = id.next;
324: } else {
325: idprev.next = id.next;
326: }
327: break;
328: }
329: idprev = id;
330: }
331: }
332:
333: public synchronized void doneDecoding(ImageDecoder mydecoder) {
334: if (decoder == mydecoder) {
335: decoder = null;
336: if (consumers != null) {
337: startProduction();
338: }
339: }
340: }
341:
342: public void latchConsumers(ImageDecoder id) {
343: doneDecoding(id);
344: }
345:
346: synchronized void flush() {
347: decoder = null;
348: }
349: }
|