001: /*
002: * Copyright 1995-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.image;
027:
028: import java.awt.image.*;
029: import java.io.InputStream;
030: import java.io.IOException;
031: import java.io.BufferedInputStream;
032: import java.util.Hashtable;
033:
034: public abstract class InputStreamImageSource implements ImageProducer,
035: ImageFetchable {
036: ImageConsumerQueue consumers;
037:
038: ImageDecoder decoder;
039: ImageDecoder decoders;
040:
041: boolean awaitingFetch = false;
042:
043: abstract boolean checkSecurity(Object context, boolean quiet);
044:
045: int countConsumers(ImageConsumerQueue cq) {
046: int i = 0;
047: while (cq != null) {
048: i++;
049: cq = cq.next;
050: }
051: return i;
052: }
053:
054: synchronized int countConsumers() {
055: ImageDecoder id = decoders;
056: int i = countConsumers(consumers);
057: while (id != null) {
058: i += countConsumers(id.queue);
059: id = id.next;
060: }
061: return i;
062: }
063:
064: public void addConsumer(ImageConsumer ic) {
065: addConsumer(ic, false);
066: }
067:
068: synchronized void printQueue(ImageConsumerQueue cq, String prefix) {
069: while (cq != null) {
070: System.out.println(prefix + cq);
071: cq = cq.next;
072: }
073: }
074:
075: synchronized void printQueues(String title) {
076: System.out.println(title + "[ -----------");
077: printQueue(consumers, " ");
078: for (ImageDecoder id = decoders; id != null; id = id.next) {
079: System.out.println(" " + id);
080: printQueue(id.queue, " ");
081: }
082: System.out.println("----------- ]" + title);
083: }
084:
085: synchronized void addConsumer(ImageConsumer ic, boolean produce) {
086: checkSecurity(null, false);
087: for (ImageDecoder id = decoders; id != null; id = id.next) {
088: if (id.isConsumer(ic)) {
089: // This consumer is already being fed.
090: return;
091: }
092: }
093: ImageConsumerQueue cq = consumers;
094: while (cq != null && cq.consumer != ic) {
095: cq = cq.next;
096: }
097: if (cq == null) {
098: cq = new ImageConsumerQueue(this , ic);
099: cq.next = consumers;
100: consumers = cq;
101: } else {
102: if (!cq.secure) {
103: Object context = null;
104: SecurityManager security = System.getSecurityManager();
105: if (security != null) {
106: context = security.getSecurityContext();
107: }
108: if (cq.securityContext == null) {
109: cq.securityContext = context;
110: } else if (!cq.securityContext.equals(context)) {
111: // If there are two different security contexts that both
112: // have a handle on the same ImageConsumer, then there has
113: // been a security breach and whether or not they trade
114: // image data is small fish compared to what they could be
115: // trading. Throw a Security exception anyway...
116: errorConsumer(cq, false);
117: throw new SecurityException(
118: "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,
138: boolean needReload) {
139: while (cq != null) {
140: if (cq.interested) {
141: errorConsumer(cq, needReload);
142: }
143: cq = cq.next;
144: }
145: }
146:
147: private void errorConsumer(ImageConsumerQueue cq, boolean needReload) {
148: cq.consumer.imageComplete(ImageConsumer.IMAGEERROR);
149: if (needReload && cq.consumer instanceof ImageRepresentation) {
150: ((ImageRepresentation) cq.consumer).image.flush();
151: }
152: removeConsumer(cq.consumer);
153: }
154:
155: public synchronized void removeConsumer(ImageConsumer ic) {
156: for (ImageDecoder id = decoders; id != null; id = id.next) {
157: id.removeConsumer(ic);
158: }
159: consumers = ImageConsumerQueue.removeConsumer(consumers, ic,
160: false);
161: }
162:
163: public void startProduction(ImageConsumer ic) {
164: addConsumer(ic, true);
165: }
166:
167: private synchronized void startProduction() {
168: if (!awaitingFetch) {
169: ImageFetcher.add(this );
170: awaitingFetch = true;
171: }
172: }
173:
174: private synchronized void stopProduction() {
175: if (awaitingFetch) {
176: ImageFetcher.remove(this );
177: awaitingFetch = false;
178: }
179: }
180:
181: public void requestTopDownLeftRightResend(ImageConsumer ic) {
182: }
183:
184: protected abstract ImageDecoder getDecoder();
185:
186: protected ImageDecoder decoderForType(InputStream is,
187: String content_type) {
188: // Don't believe the content type - file extensions can
189: // lie.
190: /*
191: if (content_type.equals("image/gif")) {
192: return new GifImageDecoder(this, is);
193: } else if (content_type.equals("image/jpeg")) {
194: return new JPEGImageDecoder(this, is);
195: } else if (content_type.equals("image/x-xbitmap")) {
196: return new XbmImageDecoder(this, is);
197: }
198: else if (content_type == URL.content_jpeg) {
199: return new JpegImageDecoder(this, is);
200: } else if (content_type == URL.content_xbitmap) {
201: return new XbmImageDecoder(this, is);
202: } else if (content_type == URL.content_xpixmap) {
203: return new Xpm2ImageDecoder(this, is);
204: }
205: */
206:
207: return null;
208: }
209:
210: protected ImageDecoder getDecoder(InputStream is) {
211: if (!is.markSupported())
212: is = new BufferedInputStream(is);
213: try {
214: /* changed to support png
215: is.mark(6);
216: */
217: is.mark(8);
218: int c1 = is.read();
219: int c2 = is.read();
220: int c3 = is.read();
221: int c4 = is.read();
222: int c5 = is.read();
223: int c6 = is.read();
224: // added to support png
225: int c7 = is.read();
226: int c8 = is.read();
227: // end of adding
228: is.reset();
229: is.mark(-1);
230:
231: if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
232: return new GifImageDecoder(this , is);
233: } else if (c1 == '\377' && c2 == '\330' && c3 == '\377') {
234: return new JPEGImageDecoder(this , is);
235: } else if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
236: return new XbmImageDecoder(this , is);
237: // } else if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
238: // c5 == 'M' && c6 == '2') {
239: // return new Xpm2ImageDecoder(this, is);
240: // added to support png
241: } else if (c1 == 137 && c2 == 80 && c3 == 78 && c4 == 71
242: && c5 == 13 && c6 == 10 && c7 == 26 && c8 == 10) {
243: return new PNGImageDecoder(this , is);
244: }
245: // end of adding
246: } catch (IOException e) {
247: }
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: synchronized void doneDecoding(ImageDecoder mydecoder) {
334: if (decoder == mydecoder) {
335: decoder = null;
336: if (consumers != null) {
337: startProduction();
338: }
339: }
340: }
341:
342: void latchConsumers(ImageDecoder id) {
343: doneDecoding(id);
344: }
345:
346: synchronized void flush() {
347: decoder = null;
348: }
349: }
|