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