View Javadoc
1   /*
2    * Copyright (c) 1995, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.awt.image;
27  
28  import java.awt.image.*;
29  import java.io.InputStream;
30  import java.io.IOException;
31  import java.io.BufferedInputStream;
32  import java.util.Hashtable;
33  
34  public 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             if (ImageFetcher.add(this)) {
168                 awaitingFetch = true;
169             } else {
170                 ImageConsumerQueue cq = consumers;
171                 consumers = null;
172                 errorAllConsumers(cq, false);
173             }
174         }
175     }
176 
177     private synchronized void stopProduction() {
178         if (awaitingFetch) {
179             ImageFetcher.remove(this);
180             awaitingFetch = false;
181         }
182     }
183 
184     public void requestTopDownLeftRightResend(ImageConsumer ic) {
185     }
186 
187     protected abstract ImageDecoder getDecoder();
188 
189     protected ImageDecoder decoderForType(InputStream is,
190                                           String content_type) {
191         // Don't believe the content type - file extensions can
192         // lie.
193         /*
194         if (content_type.equals("image/gif")) {
195             return new GifImageDecoder(this, is);
196         } else if (content_type.equals("image/jpeg")) {
197             return new JPEGImageDecoder(this, is);
198         } else if (content_type.equals("image/x-xbitmap")) {
199             return new XbmImageDecoder(this, is);
200         }
201         else if (content_type == URL.content_jpeg) {
202             return new JpegImageDecoder(this, is);
203         } else if (content_type == URL.content_xbitmap) {
204             return new XbmImageDecoder(this, is);
205         } else if (content_type == URL.content_xpixmap) {
206             return new Xpm2ImageDecoder(this, is);
207         }
208         */
209 
210         return null;
211     }
212 
213     protected ImageDecoder getDecoder(InputStream is) {
214         if (!is.markSupported())
215             is = new BufferedInputStream(is);
216         try {
217           /* changed to support png
218              is.mark(6);
219              */
220           is.mark(8);
221             int c1 = is.read();
222             int c2 = is.read();
223             int c3 = is.read();
224             int c4 = is.read();
225             int c5 = is.read();
226             int c6 = is.read();
227             // added to support png
228             int c7 = is.read();
229             int c8 = is.read();
230             // end of adding
231             is.reset();
232             is.mark(-1);
233 
234             if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
235                 return new GifImageDecoder(this, is);
236             } else if (c1 == '\377' && c2 == '\330' && c3 == '\377') {
237                 return new JPEGImageDecoder(this, is);
238             } else if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
239                 return new XbmImageDecoder(this, is);
240 //          } else if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
241 //                     c5 == 'M' && c6 == '2') {
242 //              return new Xpm2ImageDecoder(this, is);
243                 // added to support png
244             } else if (c1 == 137 && c2 == 80 && c3 == 78 &&
245                 c4 == 71 && c5 == 13 && c6 == 10 &&
246                 c7 == 26 && c8 == 10) {
247                 return new PNGImageDecoder(this, is);
248             }
249             // end of adding
250         } catch (IOException e) {
251         }
252 
253         return null;
254     }
255 
256     public void doFetch() {
257         synchronized (this) {
258             if (consumers == null) {
259                 awaitingFetch = false;
260                 return;
261             }
262         }
263         ImageDecoder imgd = getDecoder();
264         if (imgd == null) {
265             badDecoder();
266         } else {
267             setDecoder(imgd);
268             try {
269                 imgd.produceImage();
270             } catch (IOException e) {
271                 e.printStackTrace();
272                 // the finally clause will send an error.
273             } catch (ImageFormatException e) {
274                 e.printStackTrace();
275                 // the finally clause will send an error.
276             } finally {
277                 removeDecoder(imgd);
278                 if ( Thread.currentThread().isInterrupted() || !Thread.currentThread().isAlive()) {
279                     errorAllConsumers(imgd.queue, true);
280                 } else {
281                     errorAllConsumers(imgd.queue, false);
282             }
283         }
284     }
285     }
286 
287     private void badDecoder() {
288         ImageConsumerQueue cq;
289         synchronized (this) {
290             cq = consumers;
291             consumers = null;
292             awaitingFetch = false;
293         }
294         errorAllConsumers(cq, false);
295     }
296 
297     private void setDecoder(ImageDecoder mydecoder) {
298         ImageConsumerQueue cq;
299         synchronized (this) {
300             mydecoder.next = decoders;
301             decoders = mydecoder;
302             decoder = mydecoder;
303             cq = consumers;
304             mydecoder.queue = cq;
305             consumers = null;
306             awaitingFetch = false;
307         }
308         while (cq != null) {
309             if (cq.interested) {
310                 // Now that there is a decoder, security may have changed
311                 // so reverify it here, just in case.
312                 if (!checkSecurity(cq.securityContext, true)) {
313                     errorConsumer(cq, false);
314                 }
315             }
316             cq = cq.next;
317         }
318     }
319 
320     private synchronized void removeDecoder(ImageDecoder mydecoder) {
321         doneDecoding(mydecoder);
322         ImageDecoder idprev = null;
323         for (ImageDecoder id = decoders; id != null; id = id.next) {
324             if (id == mydecoder) {
325                 if (idprev == null) {
326                     decoders = id.next;
327                 } else {
328                     idprev.next = id.next;
329                 }
330                 break;
331             }
332             idprev = id;
333         }
334     }
335 
336     synchronized void doneDecoding(ImageDecoder mydecoder) {
337         if (decoder == mydecoder) {
338             decoder = null;
339             if (consumers != null) {
340                 startProduction();
341             }
342         }
343     }
344 
345     void latchConsumers(ImageDecoder id) {
346         doneDecoding(id);
347     }
348 
349     synchronized void flush() {
350         decoder = null;
351     }
352 }