| /* |
| * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.awt.image; |
| |
| import java.awt.image.*; |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.io.BufferedInputStream; |
| import java.util.Hashtable; |
| |
| public abstract class InputStreamImageSource implements ImageProducer, |
| ImageFetchable |
| { |
| ImageConsumerQueue consumers; |
| |
| ImageDecoder decoder; |
| ImageDecoder decoders; |
| |
| boolean awaitingFetch = false; |
| |
| abstract boolean checkSecurity(Object context, boolean quiet); |
| |
| int countConsumers(ImageConsumerQueue cq) { |
| int i = 0; |
| while (cq != null) { |
| i++; |
| cq = cq.next; |
| } |
| return i; |
| } |
| |
| synchronized int countConsumers() { |
| ImageDecoder id = decoders; |
| int i = countConsumers(consumers); |
| while (id != null) { |
| i += countConsumers(id.queue); |
| id = id.next; |
| } |
| return i; |
| } |
| |
| public void addConsumer(ImageConsumer ic) { |
| addConsumer(ic, false); |
| } |
| |
| synchronized void printQueue(ImageConsumerQueue cq, String prefix) { |
| while (cq != null) { |
| System.out.println(prefix+cq); |
| cq = cq.next; |
| } |
| } |
| |
| synchronized void printQueues(String title) { |
| System.out.println(title+"[ -----------"); |
| printQueue(consumers, " "); |
| for (ImageDecoder id = decoders; id != null; id = id.next) { |
| System.out.println(" "+id); |
| printQueue(id.queue, " "); |
| } |
| System.out.println("----------- ]"+title); |
| } |
| |
| synchronized void addConsumer(ImageConsumer ic, boolean produce) { |
| checkSecurity(null, false); |
| for (ImageDecoder id = decoders; id != null; id = id.next) { |
| if (id.isConsumer(ic)) { |
| // This consumer is already being fed. |
| return; |
| } |
| } |
| ImageConsumerQueue cq = consumers; |
| while (cq != null && cq.consumer != ic) { |
| cq = cq.next; |
| } |
| if (cq == null) { |
| cq = new ImageConsumerQueue(this, ic); |
| cq.next = consumers; |
| consumers = cq; |
| } else { |
| if (!cq.secure) { |
| Object context = null; |
| SecurityManager security = System.getSecurityManager(); |
| if (security != null) { |
| context = security.getSecurityContext(); |
| } |
| if (cq.securityContext == null) { |
| cq.securityContext = context; |
| } else if (!cq.securityContext.equals(context)) { |
| // If there are two different security contexts that both |
| // have a handle on the same ImageConsumer, then there has |
| // been a security breach and whether or not they trade |
| // image data is small fish compared to what they could be |
| // trading. Throw a Security exception anyway... |
| errorConsumer(cq, false); |
| throw new SecurityException("Applets are trading image data!"); |
| } |
| } |
| cq.interested = true; |
| } |
| if (produce && decoder == null) { |
| startProduction(); |
| } |
| } |
| |
| public synchronized boolean isConsumer(ImageConsumer ic) { |
| for (ImageDecoder id = decoders; id != null; id = id.next) { |
| if (id.isConsumer(ic)) { |
| return true; |
| } |
| } |
| return ImageConsumerQueue.isConsumer(consumers, ic); |
| } |
| |
| private void errorAllConsumers(ImageConsumerQueue cq, boolean needReload) { |
| while (cq != null) { |
| if (cq.interested) { |
| errorConsumer(cq, needReload); |
| } |
| cq = cq.next; |
| } |
| } |
| |
| private void errorConsumer(ImageConsumerQueue cq, boolean needReload) { |
| cq.consumer.imageComplete(ImageConsumer.IMAGEERROR); |
| if ( needReload && cq.consumer instanceof ImageRepresentation) { |
| ((ImageRepresentation)cq.consumer).image.flush(); |
| } |
| removeConsumer(cq.consumer); |
| } |
| |
| public synchronized void removeConsumer(ImageConsumer ic) { |
| for (ImageDecoder id = decoders; id != null; id = id.next) { |
| id.removeConsumer(ic); |
| } |
| consumers = ImageConsumerQueue.removeConsumer(consumers, ic, false); |
| } |
| |
| public void startProduction(ImageConsumer ic) { |
| addConsumer(ic, true); |
| } |
| |
| private synchronized void startProduction() { |
| if (!awaitingFetch) { |
| if (ImageFetcher.add(this)) { |
| awaitingFetch = true; |
| } else { |
| ImageConsumerQueue cq = consumers; |
| consumers = null; |
| errorAllConsumers(cq, false); |
| } |
| } |
| } |
| |
| private synchronized void stopProduction() { |
| if (awaitingFetch) { |
| ImageFetcher.remove(this); |
| awaitingFetch = false; |
| } |
| } |
| |
| public void requestTopDownLeftRightResend(ImageConsumer ic) { |
| } |
| |
| protected abstract ImageDecoder getDecoder(); |
| |
| protected ImageDecoder decoderForType(InputStream is, |
| String content_type) { |
| // Don't believe the content type - file extensions can |
| // lie. |
| /* |
| if (content_type.equals("image/gif")) { |
| return new GifImageDecoder(this, is); |
| } else if (content_type.equals("image/jpeg")) { |
| return new JPEGImageDecoder(this, is); |
| } else if (content_type.equals("image/x-xbitmap")) { |
| return new XbmImageDecoder(this, is); |
| } |
| else if (content_type == URL.content_jpeg) { |
| return new JpegImageDecoder(this, is); |
| } else if (content_type == URL.content_xbitmap) { |
| return new XbmImageDecoder(this, is); |
| } else if (content_type == URL.content_xpixmap) { |
| return new Xpm2ImageDecoder(this, is); |
| } |
| */ |
| |
| return null; |
| } |
| |
| protected ImageDecoder getDecoder(InputStream is) { |
| if (!is.markSupported()) |
| is = new BufferedInputStream(is); |
| try { |
| /* changed to support png |
| is.mark(6); |
| */ |
| is.mark(8); |
| int c1 = is.read(); |
| int c2 = is.read(); |
| int c3 = is.read(); |
| int c4 = is.read(); |
| int c5 = is.read(); |
| int c6 = is.read(); |
| // added to support png |
| int c7 = is.read(); |
| int c8 = is.read(); |
| // end of adding |
| is.reset(); |
| is.mark(-1); |
| |
| if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') { |
| return new GifImageDecoder(this, is); |
| } else if (c1 == '\377' && c2 == '\330' && c3 == '\377') { |
| return new JPEGImageDecoder(this, is); |
| } else if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') { |
| return new XbmImageDecoder(this, is); |
| // } else if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && |
| // c5 == 'M' && c6 == '2') { |
| // return new Xpm2ImageDecoder(this, is); |
| // added to support png |
| } else if (c1 == 137 && c2 == 80 && c3 == 78 && |
| c4 == 71 && c5 == 13 && c6 == 10 && |
| c7 == 26 && c8 == 10) { |
| return new PNGImageDecoder(this, is); |
| } |
| // end of adding |
| } catch (IOException e) { |
| } |
| |
| return null; |
| } |
| |
| public void doFetch() { |
| synchronized (this) { |
| if (consumers == null) { |
| awaitingFetch = false; |
| return; |
| } |
| } |
| ImageDecoder imgd = getDecoder(); |
| if (imgd == null) { |
| badDecoder(); |
| } else { |
| setDecoder(imgd); |
| try { |
| imgd.produceImage(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| // the finally clause will send an error. |
| } catch (ImageFormatException e) { |
| e.printStackTrace(); |
| // the finally clause will send an error. |
| } finally { |
| removeDecoder(imgd); |
| if ( Thread.currentThread().isInterrupted() || !Thread.currentThread().isAlive()) { |
| errorAllConsumers(imgd.queue, true); |
| } else { |
| errorAllConsumers(imgd.queue, false); |
| } |
| } |
| } |
| } |
| |
| private void badDecoder() { |
| ImageConsumerQueue cq; |
| synchronized (this) { |
| cq = consumers; |
| consumers = null; |
| awaitingFetch = false; |
| } |
| errorAllConsumers(cq, false); |
| } |
| |
| private void setDecoder(ImageDecoder mydecoder) { |
| ImageConsumerQueue cq; |
| synchronized (this) { |
| mydecoder.next = decoders; |
| decoders = mydecoder; |
| decoder = mydecoder; |
| cq = consumers; |
| mydecoder.queue = cq; |
| consumers = null; |
| awaitingFetch = false; |
| } |
| while (cq != null) { |
| if (cq.interested) { |
| // Now that there is a decoder, security may have changed |
| // so reverify it here, just in case. |
| if (!checkSecurity(cq.securityContext, true)) { |
| errorConsumer(cq, false); |
| } |
| } |
| cq = cq.next; |
| } |
| } |
| |
| private synchronized void removeDecoder(ImageDecoder mydecoder) { |
| doneDecoding(mydecoder); |
| ImageDecoder idprev = null; |
| for (ImageDecoder id = decoders; id != null; id = id.next) { |
| if (id == mydecoder) { |
| if (idprev == null) { |
| decoders = id.next; |
| } else { |
| idprev.next = id.next; |
| } |
| break; |
| } |
| idprev = id; |
| } |
| } |
| |
| synchronized void doneDecoding(ImageDecoder mydecoder) { |
| if (decoder == mydecoder) { |
| decoder = null; |
| if (consumers != null) { |
| startProduction(); |
| } |
| } |
| } |
| |
| void latchConsumers(ImageDecoder id) { |
| doneDecoding(id); |
| } |
| |
| synchronized void flush() { |
| decoder = null; |
| } |
| } |