1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 or later
5    * as published by the Free Software Foundation. This program is distributed
6    * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7    * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *      http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * © CrossWire Bible Society, 2005 - 2016
18   *
19   */
20  /*
21   * This is inspired by DocumentChecker.
22   * @author Andy Clark, IBM
23   * @author Arnaud Le Hors, IBM
24   *
25   * Copyright 2000-2002,2004,2005 The Apache Software Foundation.
26   *
27   * Licensed under the Apache License, Version 2.0 (the "License");
28   * you may not use this file except in compliance with the License.
29   * You may obtain a copy of the License at
30   *
31   *      http://www.apache.org/licenses/LICENSE-2.0
32   *
33   * Unless required by applicable law or agreed to in writing, software
34   * distributed under the License is distributed on an "AS IS" BASIS,
35   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36   * See the License for the specific language governing permissions and
37   * limitations under the License.
38   *
39   */
40  package org.crosswire.common.xml;
41  
42  import java.util.Locale;
43  import java.util.Map;
44  import java.util.TreeMap;
45  
46  import org.xml.sax.SAXNotRecognizedException;
47  import org.xml.sax.SAXNotSupportedException;
48  import org.xml.sax.XMLReader;
49  
50  /**
51   * A set of useful XML Features
52   * 
53   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
54   * @author DM Smith
55   */
56  public final class XMLFeatureSet {
57  
58      /**
59       * An XMLFeatureSet with default settings.
60       */
61      public XMLFeatureSet() {
62          features = new TreeMap<String, XMLFeatureState>();
63          states = new TreeMap<XMLFeature, String>();
64          features.put("n", new XMLFeatureState(XMLFeature.NAMESPACES, true));
65          features.put("np", new XMLFeatureState(XMLFeature.NAMESPACE_PREFIX));
66          features.put("v", new XMLFeatureState(XMLFeature.VALIDATION));
67          features.put("xd", new XMLFeatureState(XMLFeature.LOAD_EXTERNAL_DTD, true));
68          features.put("s", new XMLFeatureState(XMLFeature.SCHEMA_VALIDATION));
69          features.put("f", new XMLFeatureState(XMLFeature.SCHEMA_FULL_CHECKING));
70          features.put("va", new XMLFeatureState(XMLFeature.VALIDATE_ANNOTATIONS));
71          features.put("dv", new XMLFeatureState(XMLFeature.DYNAMIC_VALIDATION));
72          features.put("xi", new XMLFeatureState(XMLFeature.XINCLUDE));
73          features.put("xb", new XMLFeatureState(XMLFeature.XINCLUDE_FIXUP_BASE_URIS, true));
74          features.put("xl", new XMLFeatureState(XMLFeature.XINCLUDE_FIXUP_LANGUAGE, true));
75  
76          for (Map.Entry<String, XMLFeatureState> entry : features.entrySet()) {
77              states.put(entry.getValue().getFeature(), entry.getKey());
78          }
79      }
80  
81      /**
82       * Set the state of an XMLFeture in this set.
83       * 
84       * @param feature the XMLFeature to set
85       * @param state whether the feature is on or off
86       */
87      public void setFeatureState(XMLFeature feature, boolean state) {
88          features.get(states.get(feature)).setState(state);
89      }
90  
91      /**
92       * Allow for XMLFeatures to be set from command line.
93       * 
94       * @param argv the specification of XMLFeatures to turn on or off
95       * @see #printUsage See printUsage for details
96       */
97      public void setFeatureStates(String[] argv) {
98          // process arguments
99          for (int i = 0; i < argv.length; i++) {
100             String arg = argv[i];
101             if (arg.charAt(0) == '-') {
102                 String option = arg.substring(1);
103                 String key = option.toLowerCase(Locale.ENGLISH);
104                 XMLFeatureState feature = features.get(key);
105                 if (feature != null) {
106                     feature.setState(option.equals(key));
107                 }
108             }
109         }
110     }
111 
112     /* (non-Javadoc)
113      * @see java.lang.Object#toString()
114      */
115     @Override
116     public String toString() {
117         StringBuilder buf = new StringBuilder();
118         buf.append('\n');
119         for (XMLFeatureState state : features.values()) {
120             buf.append(state.getFeature().toString()).append('\n');
121         }
122         return buf.toString();
123     }
124 
125     /**
126      * Prints the usage.
127      */
128     public void printUsage() {
129         System.err.println("XML Feature Set options:");
130         System.err.println("  -n  | -N    Turn on/off namespace processing.");
131         System.err.println("  -np | -NP   Turn on/off namespace prefixes.");
132         System.err.println("              NOTE: Requires use of -n.");
133         System.err.println("  -v  | -V    Turn on/off validation.");
134         System.err.println("  -xd | -XD   Turn on/off loading of external DTDs.");
135         System.err.println("              NOTE: Always on when -v in use and not supported by all parsers.");
136         System.err.println("  -s  | -S    Turn on/off Schema validation support.");
137         System.err.println("              NOTE: Not supported by all parsers.");
138         System.err.println("  -f  | -F    Turn on/off Schema full checking.");
139         System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
140         System.err.println("  -va | -VA   Turn on/off validation of schema annotations.");
141         System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
142         System.err.println("  -dv | -DV   Turn on/off dynamic validation.");
143         System.err.println("              NOTE: Not supported by all parsers.");
144         System.err.println("  -xi | -XI   Turn on/off XInclude processing.");
145         System.err.println("              NOTE: Not supported by all parsers.");
146         System.err.println("  -xb | -XB   Turn on/off base URI fixup during XInclude processing.");
147         System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
148         System.err.println("  -xl | -XL   Turn on/off language fixup during XInclude processing.");
149         System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
150     }
151 
152     /**
153      * Set this XMLFeatureSets state onto an XMLReader.
154      * 
155      * @param parser the XMLReader
156      */
157     public void setFeatures(XMLReader parser) {
158         for (XMLFeatureState state : features.values()) {
159             state.setFeature(parser);
160         }
161     }
162 
163     /**
164      * A holder of the boolean state for a feature.
165      */
166     private static class XMLFeatureState {
167         /**
168          * Bind a state to an XMLFeature.
169          * 
170          * @param feature the XMLFeature
171          * @param state whether that XMLFeature is on or off
172          */
173         XMLFeatureState(XMLFeature feature, boolean state) {
174             this.feature = feature;
175             this.state = state;
176         }
177 
178         /**
179          * An XMLFeature that is turned off.
180          * @param feature the XMLFeature
181          */
182         XMLFeatureState(XMLFeature feature) {
183             this(feature, false);
184         }
185 
186         /**
187          * @return Returns the feature.
188          */
189         public XMLFeature getFeature() {
190             return feature;
191         }
192 
193         /**
194          * Set the new state
195          * 
196          * @param newState whether the feature is on or off
197          */
198         public void setState(boolean newState) {
199             state = newState;
200         }
201 
202         /**
203          * Set the control state on the parser.
204          * 
205          * @param parser The parser on which to set this feature
206          */
207         public void setFeature(XMLReader parser) {
208             String control = feature.getControl();
209             try {
210                 parser.setFeature(control, state);
211             } catch (SAXNotRecognizedException e) {
212                 System.err.println("warning: Parser does not recognize feature (" + control + ")");
213             } catch (SAXNotSupportedException e) {
214                 System.err.println("warning: Parser does not support feature (" + control + ")");
215             }
216         }
217 
218         private boolean state;
219         private XMLFeature feature;
220     }
221 
222     private Map<String, XMLFeatureState> features;
223     private Map<XMLFeature, String> states;
224 }
225