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 }