View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   // TextCatalogReader.java - Read text/plain Catalog files
6   
7   /*
8    * Copyright 2001-2004 The Apache Software Foundation or its licensors,
9    * as applicable.
10   *
11   * Licensed under the Apache License, Version 2.0 (the "License");
12   * you may not use this file except in compliance with the License.
13   * You may obtain a copy of the License at
14   *
15   *      http://www.apache.org/licenses/LICENSE-2.0
16   *
17   * Unless required by applicable law or agreed to in writing, software
18   * distributed under the License is distributed on an "AS IS" BASIS,
19   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   * See the License for the specific language governing permissions and
21   * limitations under the License.
22   */
23  
24  package com.sun.org.apache.xml.internal.resolver.readers;
25  
26  import java.io.InputStream;
27  import java.io.IOException;
28  import java.io.FileNotFoundException;
29  import java.net.URL;
30  import java.net.URLConnection;
31  import java.net.MalformedURLException;
32  import java.util.Vector;
33  import java.util.Stack;
34  import com.sun.org.apache.xml.internal.resolver.Catalog;
35  import com.sun.org.apache.xml.internal.resolver.CatalogEntry;
36  import com.sun.org.apache.xml.internal.resolver.CatalogException;
37  import com.sun.org.apache.xml.internal.resolver.readers.CatalogReader;
38  
39  /**
40   * Parses plain text Catalog files.
41   *
42   * <p>This class reads plain text Open Catalog files.</p>
43   *
44   * @see Catalog
45   *
46   * @author Norman Walsh
47   * <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
48   *
49   */
50  public class TextCatalogReader implements CatalogReader {
51    /** The input stream used to read the catalog */
52    protected InputStream catfile = null;
53  
54    /**
55     * Character lookahead stack. Reading a catalog sometimes requires
56     * up to two characters of lookahead.
57     */
58    protected int[] stack = new int[3];
59  
60    /**
61     * Token stack. Recognizing an unexpected catalog entry requires
62     * the ability to "push back" a token.
63     */
64    protected Stack tokenStack = new Stack();
65  
66    /** The current position on the lookahead stack */
67    protected int top = -1;
68  
69    /** Are keywords in the catalog case sensitive? */
70    protected boolean caseSensitive = false;
71  
72    /**
73     * Construct a CatalogReader object.
74     */
75    public TextCatalogReader() { }
76  
77    public void setCaseSensitive(boolean isCaseSensitive) {
78      caseSensitive = isCaseSensitive;
79    }
80  
81    public boolean getCaseSensitive() {
82      return caseSensitive;
83    }
84  
85    /**
86     * Start parsing a text catalog file. The file is
87     * actually read and parsed
88     * as needed by <code>nextEntry</code>.</p>
89     *
90     * @param fileUrl  The URL or filename of the catalog file to process
91     *
92     * @throws MalformedURLException Improper fileUrl
93     * @throws IOException Error reading catalog file
94     */
95    public void readCatalog(Catalog catalog, String fileUrl)
96      throws MalformedURLException, IOException {
97      URL catURL = null;
98  
99      try {
100       catURL = new URL(fileUrl);
101     } catch (MalformedURLException e) {
102       catURL = new URL("file:///" + fileUrl);
103     }
104 
105     URLConnection urlCon = catURL.openConnection();
106     try {
107       readCatalog(catalog, urlCon.getInputStream());
108     } catch (FileNotFoundException e) {
109       catalog.getCatalogManager().debug.message(1, "Failed to load catalog, file not found",
110                                                 catURL.toString());
111     }
112   }
113 
114   public void readCatalog(Catalog catalog, InputStream is)
115     throws MalformedURLException, IOException {
116 
117     catfile = is;
118 
119     if (catfile == null) {
120       return;
121     }
122 
123     Vector unknownEntry = null;
124 
125     try {
126       while (true) {
127         String token = nextToken();
128 
129         if (token == null) {
130           if (unknownEntry != null) {
131             catalog.unknownEntry(unknownEntry);
132             unknownEntry = null;
133           }
134           catfile.close();
135           catfile = null;
136           return;
137         }
138 
139         String entryToken = null;
140         if (caseSensitive) {
141           entryToken = token;
142         } else {
143           entryToken = token.toUpperCase();
144         }
145 
146         try {
147           int type = CatalogEntry.getEntryType(entryToken);
148           int numArgs = CatalogEntry.getEntryArgCount(type);
149           Vector args = new Vector();
150 
151           if (unknownEntry != null) {
152             catalog.unknownEntry(unknownEntry);
153             unknownEntry = null;
154           }
155 
156           for (int count = 0; count < numArgs; count++) {
157             args.addElement(nextToken());
158           }
159 
160           catalog.addEntry(new CatalogEntry(entryToken, args));
161         } catch (CatalogException cex) {
162           if (cex.getExceptionType() == CatalogException.INVALID_ENTRY_TYPE) {
163             if (unknownEntry == null) {
164               unknownEntry = new Vector();
165             }
166             unknownEntry.addElement(token);
167           } else if (cex.getExceptionType() == CatalogException.INVALID_ENTRY) {
168             catalog.getCatalogManager().debug.message(1, "Invalid catalog entry", token);
169             unknownEntry = null;
170           } else if (cex.getExceptionType() == CatalogException.UNENDED_COMMENT) {
171             catalog.getCatalogManager().debug.message(1, cex.getMessage());
172           }
173         }
174       }
175     } catch (CatalogException cex2) {
176       if (cex2.getExceptionType() == CatalogException.UNENDED_COMMENT) {
177         catalog.getCatalogManager().debug.message(1, cex2.getMessage());
178       }
179     }
180   }
181 
182   /**
183      * The destructor.
184      *
185      * <p>Makes sure the catalog file is closed.</p>
186      */
187   protected void finalize() {
188     if (catfile != null) {
189       try {
190         catfile.close();
191       } catch (IOException e) {
192         // whatever...
193       }
194     }
195     catfile = null;
196   }
197 
198   // -----------------------------------------------------------------
199 
200     /**
201      * Return the next token in the catalog file.
202      *
203      * <p>FYI: This code does not throw any sort of exception for
204      * a file that contains an n
205      *
206      * @return The Catalog file token from the input stream.
207      * @throws IOException If an error occurs reading from the stream.
208      */
209   protected String nextToken() throws IOException, CatalogException {
210     String token = "";
211     int ch, nextch;
212 
213     if (!tokenStack.empty()) {
214       return (String) tokenStack.pop();
215     }
216 
217     // Skip over leading whitespace and comments
218     while (true) {
219       // skip leading whitespace
220       ch = catfile.read();
221       while (ch <= ' ') {      // all ctrls are whitespace
222         ch = catfile.read();
223         if (ch < 0) {
224           return null;
225         }
226       }
227 
228       // now 'ch' is the current char from the file
229       nextch = catfile.read();
230       if (nextch < 0) {
231         return null;
232       }
233 
234       if (ch == '-' && nextch == '-') {
235         // we've found a comment, skip it...
236         ch = ' ';
237         nextch = nextChar();
238         while ((ch != '-' || nextch != '-') && nextch > 0) {
239           ch = nextch;
240           nextch = nextChar();
241         }
242 
243         if (nextch < 0) {
244           throw new CatalogException(CatalogException.UNENDED_COMMENT,
245                                      "Unterminated comment in catalog file; EOF treated as end-of-comment.");
246         }
247 
248         // Ok, we've found the end of the comment,
249         // loop back to the top and start again...
250       } else {
251         stack[++top] = nextch;
252         stack[++top] = ch;
253         break;
254       }
255     }
256 
257     ch = nextChar();
258     if (ch == '"' || ch == '\'') {
259       int quote = ch;
260       while ((ch = nextChar()) != quote) {
261         char[] chararr = new char[1];
262         chararr[0] = (char) ch;
263         String s = new String(chararr);
264         token = token.concat(s);
265       }
266       return token;
267     } else {
268       // return the next whitespace or comment delimited
269       // string
270       while (ch > ' ') {
271         nextch = nextChar();
272         if (ch == '-' && nextch == '-') {
273           stack[++top] = ch;
274           stack[++top] = nextch;
275           return token;
276         } else {
277           char[] chararr = new char[1];
278           chararr[0] = (char) ch;
279           String s = new String(chararr);
280           token = token.concat(s);
281           ch = nextch;
282         }
283       }
284       return token;
285     }
286   }
287 
288   /**
289      * Return the next logical character from the input stream.
290      *
291      * @return The next (logical) character from the input stream. The
292      * character may be buffered from a previous lookahead.
293      *
294      * @throws IOException If an error occurs reading from the stream.
295      */
296   protected int nextChar() throws IOException {
297     if (top < 0) {
298       return catfile.read();
299     } else {
300       return stack[top--];
301     }
302   }
303 }