Frames | No Frames |
1: /* ConfigFileTokenizer.java -- JAAS Login Configuration default syntax tokenizer 2: Copyright (C) 2006, 2010 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package gnu.javax.security.auth.login; 40: 41: import gnu.java.lang.CPStringBuilder; 42: 43: import gnu.java.security.Configuration; 44: 45: import java.io.BufferedReader; 46: import java.io.IOException; 47: import java.io.Reader; 48: import java.util.logging.Logger; 49: 50: /** 51: * A UTF-8 friendly, JAAS Login Module Configuration file tokenizer written in 52: * the deault syntax. This class emulates, to a certain extent, the behavior of 53: * a {@link java.io.StreamTokenizer} instance <code>st</code>, when set as 54: * follows: 55: * 56: * <pre> 57: * st.resetSyntax(); 58: * st.lowerCaseMode(false); 59: * st.slashSlashComments(true); 60: * st.slashStarComments(true); 61: * st.eolIsSignificant(false); 62: * st.wordChars('_', '_'); 63: * st.wordChars('$', '$'); 64: * st.wordChars('A', 'Z'); 65: * st.wordChars('a', 'z'); 66: * st.wordChars('0', '9'); 67: * st.wordChars('.', '.'); 68: * st.whitespaceChars(' ', ' '); 69: * st.whitespaceChars('\t', '\t'); 70: * st.whitespaceChars('\f', '\f'); 71: * st.whitespaceChars('\r', '\r'); 72: * st.whitespaceChars('\n', '\n'); 73: * st.quoteChar('"'); 74: * st.quoteChar('\''); 75: * </pre> 76: * 77: * <p>The most important (negative) difference with a 78: * {@link java.io.StreamTokenizer} is that this tokenizer does not properly 79: * handle C++ and Java // style comments in the middle of the line. It only 80: * ignores them if/when found at the start of the line.</p> 81: */ 82: public class ConfigFileTokenizer 83: { 84: private static final Logger log = Configuration.DEBUG ? 85: Logger.getLogger(ConfigFileParser.class.getName()) : null; 86: 87: /** A constant indicating that the end of the stream has been read. */ 88: public static final int TT_EOF = -1; 89: /** A constant indicating that a word token has been read. */ 90: public static final int TT_WORD = -3; 91: /** A constant indicating that no tokens have been read yet. */ 92: private static final int TT_NONE = -4; 93: 94: public String sval; 95: public int ttype; 96: 97: private final BufferedReader br; 98: boolean initialised; 99: private CPStringBuilder sb; 100: private int sbNdx; 101: 102: // Constructor(s) 103: // -------------------------------------------------------------------------- 104: 105: /** Trivial constructor. */ 106: ConfigFileTokenizer(Reader r) 107: { 108: br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r); 109: } 110: 111: // Class methods 112: // -------------------------------------------------------------------------- 113: 114: // Instance methods 115: // -------------------------------------------------------------------------- 116: 117: public int nextToken() throws IOException 118: { 119: if (!initialised) 120: init(); 121: 122: if (sbNdx >= sb.length()) 123: return TT_EOF; 124: 125: skipWhitespace(); 126: 127: if (sbNdx >= sb.length()) 128: return TT_EOF; 129: 130: int endNdx; 131: if (Character.isJavaIdentifierPart(sb.charAt(sbNdx))) 132: { 133: endNdx = sbNdx + 1; 134: while (Character.isJavaIdentifierPart(sb.charAt(endNdx)) 135: || sb.charAt(endNdx) == '.') 136: endNdx++; 137: 138: ttype = TT_WORD; 139: sval = sb.substring(sbNdx, endNdx); 140: sbNdx = endNdx; 141: return ttype; 142: } 143: 144: int c = sb.charAt(sbNdx); 145: if (c == '{' || c == '}' || c == ';' || c == '=') 146: { 147: ttype = c; 148: sbNdx++; 149: return ttype; 150: } 151: 152: if (c == '"' || c == '\'') 153: { 154: ttype = c; 155: String quote = sb.substring(sbNdx, sbNdx + 1); 156: int i = sbNdx + 1; 157: while (true) 158: { 159: // find a candidate 160: endNdx = sb.indexOf(quote, i); 161: if (endNdx == -1) 162: abort("Missing closing quote: " + quote); 163: 164: // found one; is it escaped? 165: if (sb.charAt(endNdx - 1) != '\\') 166: break; 167: 168: i++; 169: continue; 170: } 171: 172: endNdx++; 173: sval = sb.substring(sbNdx, endNdx); 174: sbNdx = endNdx; 175: return ttype; 176: } 177: 178: abort("Unknown character: " + sb.charAt(sbNdx)); 179: return Integer.MIN_VALUE; 180: } 181: 182: public void pushBack() 183: { 184: sbNdx -= ttype != TT_WORD ? 1 : sval.length(); 185: } 186: 187: private void init() throws IOException 188: { 189: sb = new CPStringBuilder(); 190: String line; 191: while ((line = br.readLine()) != null) 192: { 193: line = line.trim(); 194: if (line.length() == 0) 195: continue; 196: 197: if (line.startsWith("#") || line.startsWith("//")) 198: continue; 199: 200: sb.append(line).append(" "); 201: } 202: 203: sbNdx = 0; 204: sval = null; 205: ttype = TT_NONE; 206: 207: initialised = true; 208: } 209: 210: private void skipWhitespace() throws IOException 211: { 212: int endNdx; 213: while (sbNdx < sb.length()) 214: if (Character.isWhitespace(sb.charAt(sbNdx))) 215: { 216: sbNdx++; 217: while (sbNdx < sb.length() && Character.isWhitespace(sb.charAt(sbNdx))) 218: sbNdx++; 219: 220: continue; 221: } 222: else if (sb.charAt(sbNdx) == '/' && sb.charAt(sbNdx + 1) == '*') 223: { 224: endNdx = sb.indexOf("*/", sbNdx + 2); 225: if (endNdx == -1) 226: abort("Missing closing */ sequence"); 227: 228: sbNdx = endNdx + 2; 229: continue; 230: } 231: else 232: break; 233: } 234: 235: private void abort(String m) throws IOException 236: { 237: if (Configuration.DEBUG) 238: { 239: log.fine(m); 240: log.fine("sb = " + sb); 241: log.fine("sbNdx = " + sbNdx); 242: } 243: throw new IOException(m); 244: } 245: }