Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/batik/apps/rasterizer/Main.java


1   /*
2   
3      Copyright 2000-2003  The Apache Software Foundation 
4   
5      Licensed under the Apache License, Version 2.0 (the "License");
6      you may not use this file except in compliance with the License.
7      You may obtain a copy of the License at
8   
9          http://www.apache.org/licenses/LICENSE-2.0
10  
11     Unless required by applicable law or agreed to in writing, software
12     distributed under the License is distributed on an "AS IS" BASIS,
13     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14     See the License for the specific language governing permissions and
15     limitations under the License.
16  
17   */
18  package org.apache.batik.apps.rasterizer;
19  
20  import java.awt.Color;
21  import java.awt.geom.Rectangle2D;
22  import java.io.File;
23  import java.util.Hashtable;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.StringTokenizer;
27  import java.util.Vector;
28  
29  import org.apache.batik.transcoder.Transcoder;
30  import org.apache.batik.util.ApplicationSecurityEnforcer;
31  
32  /**
33   * Handles command line parameters to configure the <tt>SVGConverter</tt>
34   * and rasterizer images. <br />
35   *
36   * Each command line option is handled by an <tt>OptionHandler</tt> which
37   * is responsible for converting the option into a configuration of the
38   * <tt>SVGConverter</tt> which is used to perform the conversion.
39   *
40   * @author <a href="mailto:vhardy@apache.org">Vincent Hardy</a>
41   * @version $Id: Main.java,v 1.28 2004/08/18 07:12:25 vhardy Exp $
42   */
43  public class Main implements SVGConverterController {
44      /**
45       * URL for Squiggle's security policy file
46       */
47      public static final String RASTERIZER_SECURITY_POLICY
48          = "org/apache/batik/apps/rasterizer/resources/rasterizer.policy"; 
49  
50      /**
51       * Interface for handling one command line option
52       */
53      public static interface OptionHandler {
54          /**
55           * The <tt>OptionHandler</tt> should configure the <tt>SVGConverter</tt>
56           * according to the value of the option.
57           * 
58           * Should throw an IllegalArgumentException if optionValue
59           * is not an acceptable option. 
60           */
61          void handleOption(String[] optionValues, SVGConverter c);
62  
63          /**
64           * Returns the number of values which the option handler requires.
65           * This defines the length of the optionValues array passed to 
66           * the handler in the handleOption method
67           */
68          int getOptionValuesLength();
69  
70          /**
71           * Returns the description for this option
72           */
73          String getOptionDescription();
74      }
75  
76      /**
77       * This abstract implementation of the <tt>OptionHandler</tt> interface
78       * throws an exception if the number of arguments passed to the 
79       * <tt>handleOption</tt> method does not match the number of expected
80       * optionValues. If the size matches, the <tt>safeHandleOption</tt>
81       * method is invoked. 
82       * Subclasses can implement the <tt>safeHandleOption</tt> method 
83       * assuming that the input array size is correct.
84       */
85      public static abstract class AbstractOptionHandler implements OptionHandler {
86  
87          public void handleOption(String[] optionValues, SVGConverter c){
88              int nOptions = optionValues != null? optionValues.length: 0;
89              if (nOptions != getOptionValuesLength()){
90                  throw new IllegalArgumentException();
91              }
92  
93              safeHandleOption(optionValues, c);
94          }
95  
96          public abstract void safeHandleOption(String[] optionValues, SVGConverter c);
97      }
98  
99      /**
100      * Base class for options with no option value (i.e., the presence
101      * of the option means something in itself. Subclasses should implement
102      * the <tt>handleOption</tt> method which takes only an <tt>SVGConverter</tt>
103      * as a parameter.
104      */
105     public static abstract class NoValueOptionHandler extends AbstractOptionHandler {
106         public void safeHandleOption(String[] optionValues, SVGConverter c){
107             handleOption(c);
108         }
109 
110         public int getOptionValuesLength(){
111             return 0;
112         }
113 
114         public abstract void handleOption(SVGConverter c);
115     }
116 
117     /**
118      * Base class for options with a single option value. Subclasses should
119      * provide an implementation for the <tt>handleOption</tt> method which
120      * takes a <tt>String</tt> and an <tt>SVGConverter</tt> as parameters.
121      */
122     public static abstract class SingleValueOptionHandler extends AbstractOptionHandler {
123         public void safeHandleOption(String[] optionValues, SVGConverter c){
124             handleOption(optionValues[0], c);
125         }
126 
127         public int getOptionValuesLength(){
128             return 1;
129         }
130 
131         public abstract void handleOption(String optionValue, SVGConverter c);
132     }
133 
134     /**
135      * Base class for options which expect the single optionValue to 
136      * be a float. Subclasses should implement the <tt>handleOption</tt>
137      * method which takes a float and an <tt>SVGConverter</tt> as
138      * parameters.
139      */
140     public static abstract class FloatOptionHandler extends SingleValueOptionHandler {
141         public void handleOption(String optionValue, SVGConverter c){
142             try{
143                 handleOption(Float.parseFloat(optionValue), c);
144             } catch(NumberFormatException e){
145                 throw new IllegalArgumentException();
146             }
147         }
148 
149         public abstract void handleOption(float optionValue, SVGConverter c);
150     }
151 
152     /**
153      * Base class for options which expect a <tt>Rectangle</tt> optionValue.
154      * Subclasses should implement the <tt>handleOption</tt> method which
155      * takes a <tt>Rectangle</tt> and an <tt>SVGConverter</tt> as parameters.
156      */
157     public static abstract class RectangleOptionHandler extends SingleValueOptionHandler {
158         public void handleOption(String optionValue, SVGConverter c){
159             Rectangle2D r = parseRect(optionValue);
160             if (r==null){
161                 throw new IllegalArgumentException();
162             }
163             handleOption(r, c);
164         }
165 
166         public abstract void handleOption(Rectangle2D r, SVGConverter c);
167 
168         public Rectangle2D.Float parseRect(String rectValue){
169             Rectangle2D.Float rect = null;
170             if(rectValue != null){
171                 if (!rectValue.toLowerCase().endsWith("f")){
172                     rectValue += "f";
173                 }
174 
175                 StringTokenizer st = new StringTokenizer(rectValue, ",");
176                 if(st.countTokens() == 4){
177                     String xStr = st.nextToken();
178                     String yStr = st.nextToken();
179                     String wStr = st.nextToken();
180                     String hStr = st.nextToken();
181                     float x=Float.NaN, y=Float.NaN, w=Float.NaN, h=Float.NaN;
182                     try {
183                         x = Float.parseFloat(xStr);
184                         y = Float.parseFloat(yStr);
185                         w = Float.parseFloat(wStr);
186                         h = Float.parseFloat(hStr);
187                     }catch(NumberFormatException e){
188                         // If an error occured, the x, y, w, h
189                         // values will not be valid
190                     }
191                     
192                     if( !Float.isNaN(x)
193                         &&
194                         !Float.isNaN(y)
195                         &&
196                         (!Float.isNaN(w) && w > 0)
197                         &&
198                         (!Float.isNaN(h) && h > 0) ){
199                         rect = new Rectangle2D.Float(x, y, w, h);
200                     }
201                 }
202             }
203             return rect;
204         }
205     }
206 
207     /**
208      * Base class for options which expect a <tt>Color</tt> optionValue.
209      * Subclasses should implement the <tt>handleOption</tt> method which
210      * takes a <tt>Color</tt> and an <tt>SVGConverter</tt> as parameters.
211      */
212     public static abstract class ColorOptionHandler extends SingleValueOptionHandler {
213         public void handleOption(String optionValue, SVGConverter c){
214             Color color = parseARGB(optionValue);
215             if (color==null){
216                 throw new IllegalArgumentException();
217             }
218             handleOption(color, c);
219         }
220 
221         public abstract void handleOption(Color color, SVGConverter c);
222 
223         /**
224          * Parse the input value, which should be in the following
225          * format: a.r.g.b where a, r, g and b are integer values,
226          * in decimal notation, between 0 and 255.
227          * @return the parsed color if successful. null otherwise.
228          */
229         public Color parseARGB(String argbVal){
230             Color c = null;
231             if(argbVal != null){
232                 StringTokenizer st = new StringTokenizer(argbVal, ".");
233                 if(st.countTokens() == 4){
234                     String aStr = st.nextToken();
235                     String rStr = st.nextToken();
236                     String gStr = st.nextToken();
237                     String bStr = st.nextToken();
238                     int a = -1, r = -1, g = -1, b = -1;
239                     try {
240                         a = Integer.parseInt(aStr);
241                         r = Integer.parseInt(rStr);
242                         g = Integer.parseInt(gStr);
243                         b = Integer.parseInt(bStr);
244                     }catch(NumberFormatException e){
245                         // If an error occured, the a, r, g, b
246                         // values will not be in the 0-255 range
247                         // and the next if test will fail
248                     }
249                     
250                     if( a>=0 && a<=255
251                         &&
252                         r>=0 && r<=255
253                         &&
254                         g>=0 && g<=255
255                         &&
256                         b>=0 && b<=255 ){
257                         c = new Color(r,g,b,a);
258                     }
259                 }
260             }
261             return c;
262         }
263     }
264 
265 
266 
267     /**
268      * Describes the command line options for the rasterizer
269      */
270     public static String USAGE =
271         Messages.formatMessage("Main.usage", null);
272 
273     //
274     // The command line options are found in the properties
275     // file.
276     //
277 
278     /**
279      * Option to specify the output directory or file
280      */
281     public static String CL_OPTION_OUTPUT
282         = Messages.get("Main.cl.option.output", "-d");
283 
284     public static String CL_OPTION_OUTPUT_DESCRIPTION
285         = Messages.get("Main.cl.option.output.description", "No description");
286 
287     /**
288      * Option to specify the output image's mime type
289      */
290     public static String CL_OPTION_MIME_TYPE
291         = Messages.get("Main.cl.option.mime.type", "-m");
292 
293     public static String CL_OPTION_MIME_TYPE_DESCRIPTION
294         = Messages.get("Main.cl.option.mime.type.description", "No description");
295 
296     /**
297      * Option to specify the output image's width
298      */
299     public static String CL_OPTION_WIDTH 
300         = Messages.get("Main.cl.option.width", "-w");
301 
302     public static String CL_OPTION_WIDTH_DESCRIPTION
303         = Messages.get("Main.cl.option.width.description", "No description");
304 
305     /**
306      * Option to specify the output image's height
307      */
308     public static String CL_OPTION_HEIGHT
309         = Messages.get("Main.cl.option.height", "-h");
310 
311     public static String CL_OPTION_HEIGHT_DESCRIPTION
312         = Messages.get("Main.cl.option.height.description", "No description");
313 
314     /**
315      * Option to specify the output image's maximum width.
316      */
317     public static String CL_OPTION_MAX_WIDTH 
318         = Messages.get("Main.cl.option.max.width", "-maxw");
319 
320     public static String CL_OPTION_MAX_WIDTH_DESCRIPTION
321         = Messages.get("Main.cl.option.max.width.description", "No description");
322 
323     /**
324      * Option to specify the output image's maximum height.
325      */
326     public static String CL_OPTION_MAX_HEIGHT
327         = Messages.get("Main.cl.option.max.height", "-maxh");
328 
329     public static String CL_OPTION_MAX_HEIGHT_DESCRIPTION
330         = Messages.get("Main.cl.option.max.height.description", "No description");
331 
332     /**
333      * Option to specify the area of interest in the output 
334      * image.
335      */
336     public static String CL_OPTION_AOI
337         = Messages.get("Main.cl.option.aoi", "-a");
338 
339     public static String CL_OPTION_AOI_DESCRIPTION
340         = Messages.get("Main.cl.option.aoi.description", "No description");
341 
342     /**
343      * Option to specify the output image's background color
344      */
345     public static String CL_OPTION_BACKGROUND_COLOR
346         = Messages.get("Main.cl.option.background.color", "-bg");
347 
348     public static String CL_OPTION_BACKGROUND_COLOR_DESCRIPTION
349         = Messages.get("Main.cl.option.background.color.description", "No description");
350 
351     /**
352      * Option to specify the CSS media type when converting
353      * the SVG image
354      */
355     public static String CL_OPTION_MEDIA_TYPE
356         = Messages.get("Main.cl.option.media.type", "-cssMedia");
357 
358     public static String CL_OPTION_MEDIA_TYPE_DESCRIPTION
359         = Messages.get("Main.cl.option.media.type.description", "No description");
360 
361     /**
362      * Option to specify the default value for the font-family
363      * CSS property when converting the SVG image
364      */
365     public static String CL_OPTION_DEFAULT_FONT_FAMILY
366         = Messages.get("Main.cl.option.default.font.family", "-font-family");
367 
368     public static String CL_OPTION_DEFAULT_FONT_FAMILY_DESCRIPTION
369         = Messages.get("Main.cl.option.default.font.family.description", "No description");
370 
371     /**
372      * Option to specify the CSS alternate stylesheet when
373      * converting the SVG images
374      */
375     public static String CL_OPTION_ALTERNATE_STYLESHEET
376         = Messages.get("Main.cl.option.alternate.stylesheet", "-cssAlternate");
377 
378     public static String CL_OPTION_ALTERNATE_STYLESHEET_DESCRIPTION
379         = Messages.get("Main.cl.option.alternate.stylesheet.description", "No description");
380 
381     /**
382      * Option to specify that the converted SVG files should
383      * be validated during the conversion process.
384      */
385     public static String CL_OPTION_VALIDATE
386         = Messages.get("Main.cl.option.validate", "-validate");
387       
388     public static String CL_OPTION_VALIDATE_DESCRIPTION
389         = Messages.get("Main.cl.option.validate.description", "No description");
390 
391     /**
392      * Option to specify that the converted SVG files should
393      * be after the dispatch of the 'onload' event.
394      */
395     public static String CL_OPTION_ONLOAD
396         = Messages.get("Main.cl.option.onload", "-onload");
397       
398     public static String CL_OPTION_ONLOAD_DESCRIPTION
399         = Messages.get("Main.cl.option.onload.description", "No description");
400 
401     /**
402      * Option to specify the user language with which SVG
403      * documents should be processed
404      */
405     public static String CL_OPTION_LANGUAGE
406         = Messages.get("Main.cl.option.language", "-lang");
407 
408     public static String CL_OPTION_LANGUAGE_DESCRIPTION
409         = Messages.get("Main.cl.option.language.description", "No description");
410 
411     /**
412      * Option to specify an addition user stylesheet
413      */
414     public static String CL_OPTION_USER_STYLESHEET
415         = Messages.get("Main.cl.option.user.stylesheet", "-cssUser");
416 
417     public static String CL_OPTION_USER_STYLESHEET_DESCRIPTION
418         = Messages.get("Main.cl.option.user.stylesheet.description", "No description");
419 
420     /**
421      * Option to specify the resolution for the output image
422      */
423     public static String CL_OPTION_DPI
424         = Messages.get("Main.cl.option.dpi", "-dpi");
425 
426     public static String CL_OPTION_DPI_DESCRIPTION
427         = Messages.get("Main.cl.option.dpi.description", "No description");
428 
429     /**
430      * Option to specify the output JPEG quality
431      */
432     public static String CL_OPTION_QUALITY
433         = Messages.get("Main.cl.option.quality", "-q");
434 
435     public static String CL_OPTION_QUALITY_DESCRIPTION
436         = Messages.get("Main.cl.option.quality.description", "No description");
437 
438     /**
439      * Option to specify if the PNG should be indexed.
440      */
441     public static String CL_OPTION_INDEXED
442         = Messages.get("Main.cl.option.indexed", "-indexed");
443 
444     public static String CL_OPTION_INDEXED_DESCRIPTION
445         = Messages.get("Main.cl.option.indexed.description", "No description");
446 
447     /**
448      * Option to specify the set of allowed scripts
449      */
450     public static String CL_OPTION_ALLOWED_SCRIPTS
451         = Messages.get("Main.cl.option.allowed.scripts", "-scripts");
452 
453     public static String CL_OPTION_ALLOWED_SCRIPTS_DESCRIPTION
454         = Messages.get("Main.cl.option.allowed.scripts.description", "No description");
455 
456     /**
457      * Option to determine whether scripts a constrained to the 
458      * same origin as the document referencing them.
459      */
460     public static String CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN
461         = Messages.get("Main.cl.option.constrain.script.origin", "-anyScriptOrigin");
462 
463     public static String CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN_DESCRIPTION
464         = Messages.get("Main.cl.option.constrain.script.origin.description", "No description");
465 
466     /**
467      * Option to turn off secure execution of scripts
468      */
469     public static String CL_OPTION_SECURITY_OFF
470         = Messages.get("Main.cl.option.security.off", "-scriptSecurityOff");
471     
472     public static String CL_OPTION_SECURITY_OFF_DESCRIPTION
473         = Messages.get("Main.cl.option.security.off.description", "No description");
474 
475     /**
476      * Static map containing all the option handlers able to analyze the
477      * various options.
478      */
479     protected static Map optionMap = new Hashtable();
480 
481     /**
482      * Static map containing all the mime types understood by the 
483      * rasterizer
484      */
485     protected static Map mimeTypeMap = new Hashtable();
486 
487     /**
488      * Static initializer: adds all the option handlers to the 
489      * map of option handlers.
490      */
491     static {
492         mimeTypeMap.put("image/jpg", DestinationType.JPEG);
493         mimeTypeMap.put("image/jpeg", DestinationType.JPEG);
494         mimeTypeMap.put("image/jpe", DestinationType.JPEG);
495         mimeTypeMap.put("image/png", DestinationType.PNG);
496         mimeTypeMap.put("application/pdf", DestinationType.PDF);
497         mimeTypeMap.put("image/tiff", DestinationType.TIFF);
498 
499         optionMap.put(CL_OPTION_OUTPUT,
500                       new SingleValueOptionHandler(){
501                               public void handleOption(String optionValue, 
502                                                        SVGConverter c){
503                                   c.setDst(new File(optionValue));
504                               }
505                               public String getOptionDescription(){
506                                   return CL_OPTION_OUTPUT_DESCRIPTION;
507                               }
508                           });
509 
510         optionMap.put(CL_OPTION_MIME_TYPE,
511                       new SingleValueOptionHandler(){
512                               public void handleOption(String optionValue,
513                                                        SVGConverter c){
514                                   DestinationType dstType = 
515                                       (DestinationType)mimeTypeMap.get(optionValue);
516 
517                                   if (dstType == null){
518                                       throw new IllegalArgumentException();
519                                   }
520 
521                                   c.setDestinationType(dstType);
522                               }
523 
524                               public String getOptionDescription(){
525                                   return CL_OPTION_MIME_TYPE_DESCRIPTION;
526                               }
527                           });
528 
529         optionMap.put(CL_OPTION_WIDTH,
530                       new FloatOptionHandler(){
531                               public void handleOption(float optionValue,
532                                                        SVGConverter c){
533                                   if (optionValue <= 0){
534                                       throw new IllegalArgumentException();
535                                   }
536 
537                                   c.setWidth(optionValue);
538                               }
539 
540                               public String getOptionDescription(){
541                                   return CL_OPTION_WIDTH_DESCRIPTION;
542                               }
543                           });
544 
545         optionMap.put(CL_OPTION_HEIGHT,
546                       new FloatOptionHandler(){
547                               public void handleOption(float optionValue,
548                                                        SVGConverter c){
549                                   if (optionValue <= 0){
550                                       throw new IllegalArgumentException();
551                                   }
552 
553                                   c.setHeight(optionValue);
554                               }
555 
556                               public String getOptionDescription(){
557                                   return CL_OPTION_HEIGHT_DESCRIPTION;
558                               }
559                           });
560 
561         optionMap.put(CL_OPTION_MAX_WIDTH,
562                       new FloatOptionHandler(){
563                               public void handleOption(float optionValue,
564                                                        SVGConverter c){
565                                   if (optionValue <= 0){
566                                       throw new IllegalArgumentException();
567                                   }
568 
569                                   c.setMaxWidth(optionValue);
570                               }
571 
572                               public String getOptionDescription(){
573                                   return CL_OPTION_MAX_WIDTH_DESCRIPTION;
574                               }
575                           });
576 
577         optionMap.put(CL_OPTION_MAX_HEIGHT,
578                       new FloatOptionHandler(){
579                               public void handleOption(float optionValue,
580                                                        SVGConverter c){
581                                   if (optionValue <= 0){
582                                       throw new IllegalArgumentException();
583                                   }
584 
585                                   c.setMaxHeight(optionValue);
586                               }
587 
588                               public String getOptionDescription(){
589                                   return CL_OPTION_MAX_HEIGHT_DESCRIPTION;
590                               }
591                           });
592 
593         optionMap.put(CL_OPTION_AOI,
594                       new RectangleOptionHandler(){
595                               public void handleOption(Rectangle2D optionValue,
596                                                        SVGConverter c){
597                                   c.setArea(optionValue);
598                               }
599 
600                               public String getOptionDescription(){
601                                   return CL_OPTION_AOI_DESCRIPTION;
602                               }
603                           });
604 
605         optionMap.put(CL_OPTION_BACKGROUND_COLOR,
606                       new ColorOptionHandler(){
607                               public void handleOption(Color optionValue,
608                                                        SVGConverter c){
609                                   c.setBackgroundColor(optionValue);
610                               }
611 
612                               public String getOptionDescription(){
613                                   return CL_OPTION_BACKGROUND_COLOR_DESCRIPTION;
614                               }
615                           });
616 
617         optionMap.put(CL_OPTION_MEDIA_TYPE,
618                       new SingleValueOptionHandler(){
619                               public void handleOption(String optionValue,
620                                                        SVGConverter c){
621                                   c.setMediaType(optionValue);
622                               }
623 
624                               public String getOptionDescription(){
625                                   return CL_OPTION_MEDIA_TYPE_DESCRIPTION;
626                               }
627                           });
628 
629         optionMap.put(CL_OPTION_DEFAULT_FONT_FAMILY,
630                       new SingleValueOptionHandler() {
631                           public void handleOption(String optionValue,
632                                                    SVGConverter c){
633                               c.setDefaultFontFamily(optionValue);
634                           }
635 
636                           public String getOptionDescription(){
637                               return CL_OPTION_DEFAULT_FONT_FAMILY_DESCRIPTION;
638                           }
639                       });
640 
641         optionMap.put(CL_OPTION_ALTERNATE_STYLESHEET,
642                       new SingleValueOptionHandler(){
643                               public void handleOption(String optionValue,
644                                                        SVGConverter c){
645                                   c.setAlternateStylesheet(optionValue);
646                               }
647 
648                               public String getOptionDescription(){
649                                   return CL_OPTION_ALTERNATE_STYLESHEET_DESCRIPTION;
650                               }
651                           });
652 
653         optionMap.put(CL_OPTION_USER_STYLESHEET,
654                       new SingleValueOptionHandler(){
655                               public void handleOption(String optionValue,
656                                                        SVGConverter c){
657                                   c.setUserStylesheet(optionValue);
658                               }
659 
660                               public String getOptionDescription(){
661                                   return CL_OPTION_USER_STYLESHEET_DESCRIPTION;
662                               }
663                           });
664 
665         optionMap.put(CL_OPTION_LANGUAGE,
666                       new SingleValueOptionHandler(){
667                               public void handleOption(String optionValue,
668                                                        SVGConverter c){
669                                   c.setLanguage(optionValue);
670                               }
671 
672                               public String getOptionDescription(){
673                                   return CL_OPTION_LANGUAGE_DESCRIPTION;
674                               }
675                           });
676 
677         optionMap.put(CL_OPTION_DPI,
678                       new FloatOptionHandler(){
679                               public void handleOption(float optionValue,
680                                                        SVGConverter c){
681                                   if (optionValue <= 0){
682                                       throw new IllegalArgumentException();
683                                   }
684 
685                                   c.setPixelUnitToMillimeter
686                                       ((2.54f/optionValue)*10);
687                               }
688 
689                               public String getOptionDescription(){
690                                   return CL_OPTION_DPI_DESCRIPTION;
691                               }
692                           });
693         
694         optionMap.put(CL_OPTION_QUALITY,
695                       new FloatOptionHandler(){
696                               public void handleOption(float optionValue,
697                                                        SVGConverter c){
698                                   if (optionValue <= 0 || optionValue >= 1){
699                                       throw new IllegalArgumentException();
700                                   }
701 
702                                   c.setQuality(optionValue);
703                               }
704 
705                               public String getOptionDescription(){
706                                   return CL_OPTION_QUALITY_DESCRIPTION;
707                               }
708                           });
709 
710         optionMap.put(CL_OPTION_INDEXED,
711                       new FloatOptionHandler(){
712                               public void handleOption(float optionValue, 
713                                                        SVGConverter c){
714                                   if ((optionValue != 1) &&
715                                       (optionValue != 2) &&
716                                       (optionValue != 4) &&
717                                       (optionValue != 8)) 
718                                       throw new IllegalArgumentException();
719 
720                                   c.setIndexed((int)optionValue);
721                               }
722                       
723                               public String getOptionDescription(){
724                                   return CL_OPTION_INDEXED_DESCRIPTION;
725                               }
726                           });
727         optionMap.put(CL_OPTION_VALIDATE,
728                       new NoValueOptionHandler(){
729                               public void handleOption(SVGConverter c){
730                                   c.setValidate(true);
731                              }
732 
733                               public String getOptionDescription(){
734                                   return CL_OPTION_VALIDATE_DESCRIPTION;
735                               }
736                           });
737         optionMap.put(CL_OPTION_ONLOAD,
738                       new NoValueOptionHandler(){
739                               public void handleOption(SVGConverter c){
740                                   c.setExecuteOnload(true);
741                              }
742 
743                               public String getOptionDescription(){
744                                   return CL_OPTION_ONLOAD_DESCRIPTION;
745                               }
746                           });
747 
748         optionMap.put(CL_OPTION_ALLOWED_SCRIPTS,
749                       new SingleValueOptionHandler() {
750                           public void handleOption(String optionValue,
751                                                    SVGConverter c){
752                               c.setAllowedScriptTypes(optionValue);
753                           }
754                           
755                           public String getOptionDescription(){
756                               return CL_OPTION_ALLOWED_SCRIPTS_DESCRIPTION;
757                           }
758                       });
759         
760         optionMap.put(CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN,
761                       new NoValueOptionHandler(){
762                           public void handleOption(SVGConverter c){
763                               c.setConstrainScriptOrigin(false);
764                           }
765 
766                           public String getOptionDescription(){
767                               return CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN_DESCRIPTION;
768                           }
769                       });
770                                                 
771         optionMap.put(CL_OPTION_SECURITY_OFF,
772                       new NoValueOptionHandler() {
773                           public void handleOption(SVGConverter c){
774                               c.setSecurityOff(true);
775                           }
776 
777                           public String getOptionDescription(){
778                               return CL_OPTION_SECURITY_OFF_DESCRIPTION;
779                           }
780                       });
781     }
782       
783     /**
784      * Vector of arguments describing the conversion task to be
785      * performed.
786      */
787     protected Vector args;
788 
789     public Main(String[] args){
790         this.args = new Vector();
791         for (int i=0; i<args.length; i++){
792             this.args.addElement(args[i]);
793         }
794     }
795 
796     protected void error(String errorCode,
797                          Object[] errorArgs){
798         System.err.println(Messages.formatMessage(errorCode,
799                                                   errorArgs));
800     }
801 
802     //
803     // Error codes generated by the rasterizer
804     //
805 
806     /**
807      * Error when there are missing option values:
808      * {0} Option
809      * {1} Option description  
810      */
811     public static final String ERROR_NOT_ENOUGH_OPTION_VALUES
812         = "Main.error.not.enough.option.values";
813 
814     /**
815      * Error when an illegal option value was passed to the app
816      * {0} Option
817      * {1} Option description  
818      */
819     public static final String ERROR_ILLEGAL_ARGUMENT
820         = "Main.error.illegal.argument";
821 
822     public static final String ERROR_WHILE_CONVERTING_FILES
823         = "Main.error.while.converting.files";
824 
825     public void execute(){
826         SVGConverter c = new SVGConverter(this);
827 
828         Vector sources = new Vector();
829 
830         int nArgs = args.size();
831         for (int i=0; i<nArgs; i++){
832             String v = (String)args.elementAt(i);
833             OptionHandler optionHandler = (OptionHandler)optionMap.get(v);
834             if (optionHandler == null){
835                 // Assume v is a source.
836                 sources.addElement(v);
837             } else {
838                 // v is an option. Extract the optionValues required
839                 // by the handler.
840                 int nOptionArgs = optionHandler.getOptionValuesLength();
841                 if (i + nOptionArgs >= nArgs){
842                     error(ERROR_NOT_ENOUGH_OPTION_VALUES, new Object[]{ v, optionHandler.getOptionDescription()});
843                     return;
844                 } 
845 
846                 String[] optionValues = new String[nOptionArgs];
847                 for (int j=0; j<nOptionArgs; j++){
848                     optionValues[j] = (String)args.elementAt(1+i+j);
849                 }
850                 i += nOptionArgs;
851 
852                 try {
853                     optionHandler.handleOption(optionValues, c);
854                 } catch(IllegalArgumentException e){
855                     e.printStackTrace();
856                     error(ERROR_ILLEGAL_ARGUMENT,
857                           new Object[] { v,
858                                          optionHandler.getOptionDescription() ,
859                                          toString(optionValues)});
860                     return;
861                 }
862             }
863         }
864 
865         // Apply script security option
866         ApplicationSecurityEnforcer securityEnforcer = 
867             new ApplicationSecurityEnforcer(this.getClass(),
868                                             RASTERIZER_SECURITY_POLICY);
869 
870         securityEnforcer.enforceSecurity(!c.getSecurityOff());
871 
872         String expandedSources[] = expandSources(sources);
873 
874         c.setSources(expandedSources);
875 
876         validateConverterConfig(c);
877 
878         if (expandedSources== null || expandedSources.length < 1){
879             System.out.println(USAGE);
880             System.out.flush();
881             securityEnforcer.enforceSecurity(false);
882             return;
883         }
884 
885         try {
886             c.execute();
887         } catch(SVGConverterException e){
888             error(ERROR_WHILE_CONVERTING_FILES,
889                   new Object[] { e.getMessage() });
890         } finally {
891             System.out.flush();
892             securityEnforcer.enforceSecurity(false);
893         }
894     }
895 
896     protected String toString(String[] v){
897         StringBuffer sb = new StringBuffer();
898         int n = v != null ? v.length:0;
899         for (int i=0; i<n; i++){
900             sb.append(v[i] + " ");
901         }
902 
903         return sb.toString();
904     }
905 
906     /**
907      * Template methods which subclasses may implement to do whatever is
908      * needed. For example, this can be used for test purposes.
909      */
910     public void validateConverterConfig(SVGConverter c){
911     }
912 
913     /**
914      * Scans the input vector and replaces directories with the list
915      * of SVG files they contain
916      */
917     protected String[] expandSources(Vector sources){
918         Vector expandedSources = new Vector();
919         Iterator iter = sources.iterator();
920         while (iter.hasNext()){
921             String v = (String)iter.next();
922             File f = new File(v);
923             if (f.exists() && f.isDirectory()){
924                 File[] fl = f.listFiles(new SVGConverter.SVGFileFilter());
925                 for (int i=0; i<fl.length; i++){
926                     expandedSources.addElement(fl[i].getPath());
927                 }
928             } else {
929                 expandedSources.addElement(v);
930             }
931         }
932 
933         String[] s = new String[expandedSources.size()];
934         expandedSources.copyInto(s);
935         return s;
936     }
937 
938     public static void main(String [] args) {
939         (new Main(args)).execute();
940         System.exit(0);
941     }
942 
943     //
944     // SVGConverterController implementation
945     //
946     public static final String MESSAGE_ABOUT_TO_TRANSCODE
947         = "Main.message.about.to.transcode";
948 
949     public static final String MESSAGE_ABOUT_TO_TRANSCODE_SOURCE
950         = "Main.message.about.to.transcode.source";
951 
952     public static final String MESSAGE_CONVERSION_FAILED
953         = "Main.message.conversion.failed";
954 
955     public static final String MESSAGE_CONVERSION_SUCCESS
956         = "Main.message.conversion.success";
957 
958     public boolean proceedWithComputedTask(Transcoder transcoder,
959                                            Map hints,
960                                            Vector sources,
961                                            Vector dest){
962         System.out.println(Messages.formatMessage(MESSAGE_ABOUT_TO_TRANSCODE,
963                                                   new Object[]{"" + sources.size()}));
964         return true;
965     }
966 
967     public boolean proceedWithSourceTranscoding(SVGConverterSource source,
968                                                 File dest){
969         System.out.print(Messages.formatMessage(MESSAGE_ABOUT_TO_TRANSCODE_SOURCE,
970                                                 new Object[]{source.toString(),
971                                                              dest.toString()}));
972         return true;
973     }     
974         
975     public boolean proceedOnSourceTranscodingFailure(SVGConverterSource source,
976                                                      File dest,
977                                                      String errorCode){
978         System.out.println(Messages.formatMessage(MESSAGE_CONVERSION_FAILED,
979                                                   new Object[]{errorCode}));
980 
981         return true;
982     }
983 
984     public void onSourceTranscodingSuccess(SVGConverterSource source,
985                                            File dest){
986         System.out.println(Messages.formatMessage(MESSAGE_CONVERSION_SUCCESS,
987                                                   null));
988     }
989 }
990