1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen//
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// Copyright (C) 2003-2004 Nominum, Inc.
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen//
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// Permission to use, copy, modify, and distribute this software for any
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// purpose with or without fee is hereby granted, provided that the above
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// copyright notice and this permission notice appear in all copies.
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen//
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR ANY
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen//
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.xbill.DNS;
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.*;
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.*;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.utils.*;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Tokenizer is used to parse DNS records and zones from text format,
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Brian Wellington
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Bob Halley
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class Tokenizer {
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static String delim = " \t\n;()\"";
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static String quotes = "\"";
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** End of file */
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int EOF		= 0;
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** End of line */
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int EOL		= 1;
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Whitespace; only returned when wantWhitespace is set */
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int WHITESPACE	= 2;
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** An identifier (unquoted string) */
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int IDENTIFIER	= 3;
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** A quoted string */
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int QUOTED_STRING	= 4;
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** A comment; only returned when wantComment is set */
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int COMMENT		= 5;
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate PushbackInputStream is;
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate boolean ungottenToken;
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate int multiline;
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate boolean quoting;
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate String delimiters;
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate Token current;
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate StringBuffer sb;
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate boolean wantClose;
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate String filename;
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate int line;
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static class Token {
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/** The type of token. */
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public int type;
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/** The value of the token, or null for tokens without values. */
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public String value;
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	private
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Token() {
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		type = -1;
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		value = null;
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	private Token
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	set(int type, StringBuffer value) {
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (type < 0)
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw new IllegalArgumentException();
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		this.type = type;
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		this.value = value == null ? null : value.toString();
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return this;
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Converts the token to a string containing a representation useful
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * for debugging.
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public String
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	toString() {
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		switch (type) {
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		case EOF:
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return "<eof>";
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		case EOL:
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return "<eol>";
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		case WHITESPACE:
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return "<whitespace>";
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		case IDENTIFIER:
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return "<identifier: " + value + ">";
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		case QUOTED_STRING:
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return "<quoted_string: " + value + ">";
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		case COMMENT:
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return "<comment: " + value + ">";
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		default:
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return "<unknown>";
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/** Indicates whether this token contains a string. */
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public boolean
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	isString() {
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return (type == IDENTIFIER || type == QUOTED_STRING);
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/** Indicates whether this token contains an EOL or EOF. */
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public boolean
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	isEOL() {
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return (type == EOL || type == EOF);
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenstatic class TokenizerException extends TextParseException {
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String message;
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	TokenizerException(String filename, int line, String message) {
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		super(filename + ":" + line + ": " + message);
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		this.message = message;
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public String
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	getBaseMessage() {
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return message;
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a Tokenizer from an arbitrary input stream.
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param is The InputStream to tokenize.
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenTokenizer(InputStream is) {
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (!(is instanceof BufferedInputStream))
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		is = new BufferedInputStream(is);
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	this.is = new PushbackInputStream(is, 2);
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	ungottenToken = false;
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	multiline = 0;
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	quoting = false;
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	delimiters = delim;
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	current = new Token();
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	sb = new StringBuffer();
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	filename = "<none>";
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	line = 1;
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a Tokenizer from a string.
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param s The String to tokenize.
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenTokenizer(String s) {
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	this(new ByteArrayInputStream(s.getBytes()));
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a Tokenizer from a file.
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param f The File to tokenize.
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenTokenizer(File f) throws FileNotFoundException {
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	this(new FileInputStream(f));
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	wantClose = true;
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	filename = f.getName();
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate int
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetChar() throws IOException {
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int c = is.read();
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (c == '\r') {
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		int next = is.read();
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (next != '\n')
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			is.unread(next);
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		c = '\n';
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (c == '\n')
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		line++;
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return c;
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate void
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenungetChar(int c) throws IOException {
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (c == -1)
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return;
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	is.unread(c);
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (c == '\n')
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		line--;
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate int
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenskipWhitespace() throws IOException {
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int skipped = 0;
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	while (true) {
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		int c = getChar();
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (c != ' ' && c != '\t') {
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	                if (!(c == '\n' && multiline > 0)) {
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				ungetChar(c);
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return skipped;
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		skipped++;
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate void
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChencheckUnbalancedParens() throws TextParseException {
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (multiline > 0)
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("unbalanced parentheses");
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer.
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param wantWhitespace If true, leading whitespace will be returned as a
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * token.
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param wantComment If true, comments are returned as tokens.
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream.
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Token
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenget(boolean wantWhitespace, boolean wantComment) throws IOException {
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int type;
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int c;
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (ungottenToken) {
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		ungottenToken = false;
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (current.type == WHITESPACE) {
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (wantWhitespace)
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return current;
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		} else if (current.type == COMMENT) {
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (wantComment)
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return current;
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		} else {
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (current.type == EOL)
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				line++;
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return current;
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int skipped = skipWhitespace();
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (skipped > 0 && wantWhitespace)
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return current.set(WHITESPACE, null);
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	type = IDENTIFIER;
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	sb.setLength(0);
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	while (true) {
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		c = getChar();
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (c == -1 || delimiters.indexOf(c) != -1) {
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (c == -1) {
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (quoting)
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					throw exception("EOF in " +
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen							"quoted string");
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				else if (sb.length() == 0)
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					return current.set(EOF, null);
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				else
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					return current.set(type, sb);
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (sb.length() == 0 && type != QUOTED_STRING) {
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (c == '(') {
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					multiline++;
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					skipWhitespace();
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					continue;
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				} else if (c == ')') {
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					if (multiline <= 0)
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						throw exception("invalid " +
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen								"close " +
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen								"parenthesis");
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					multiline--;
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					skipWhitespace();
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					continue;
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				} else if (c == '"') {
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					if (!quoting) {
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						quoting = true;
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						delimiters = quotes;
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						type = QUOTED_STRING;
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					} else {
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						quoting = false;
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						delimiters = delim;
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						skipWhitespace();
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					}
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					continue;
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				} else if (c == '\n') {
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					return current.set(EOL, null);
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				} else if (c == ';') {
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					while (true) {
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						c = getChar();
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						if (c == '\n' || c == -1)
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen							break;
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						sb.append((char)c);
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					}
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					if (wantComment) {
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						ungetChar(c);
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						return current.set(COMMENT, sb);
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					} else if (c == -1 &&
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						   type != QUOTED_STRING)
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					{
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						checkUnbalancedParens();
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						return current.set(EOF, null);
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					} else if (multiline > 0) {
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						skipWhitespace();
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						sb.setLength(0);
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						continue;
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					} else
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						return current.set(EOL, null);
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				} else
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					throw new IllegalStateException();
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			} else
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				ungetChar(c);
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			break;
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		} else if (c == '\\') {
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			c = getChar();
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (c == -1)
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				throw exception("unterminated escape sequence");
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			sb.append('\\');
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		} else if (quoting && c == '\n') {
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw exception("newline in quoted string");
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		sb.append((char)c);
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (sb.length() == 0 && type != QUOTED_STRING) {
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		checkUnbalancedParens();
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return current.set(EOF, null);
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return current.set(type, sb);
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer, ignoring whitespace and comments.
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream.
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Token
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenget() throws IOException {
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return get(false, false);
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a token to the stream, so that it will be returned by the next call
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to get().
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IllegalStateException There are already ungotten tokens.
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenunget() {
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (ungottenToken)
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw new IllegalStateException
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				("Cannot unget multiple tokens");
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (current.type == EOL)
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		line--;
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	ungottenToken = true;
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and converts it to a string.
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as a string.
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not a string.
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic String
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetString() throws IOException {
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Token next = get();
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (!next.isString()) {
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected a string");
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return next.value;
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate String
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen_getIdentifier(String expected) throws IOException {
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Token next = get();
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (next.type != IDENTIFIER)
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected " + expected);
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return next.value;
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer, ensures it is an unquoted string,
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * and converts it to a string.
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as a string.
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not an unquoted string.
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic String
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetIdentifier() throws IOException {
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return _getIdentifier("an identifier");
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and converts it to a long.
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as a long.
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not a long.
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic long
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetLong() throws IOException {
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String next = _getIdentifier("an integer");
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (!Character.isDigit(next.charAt(0)))
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected an integer");
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return Long.parseLong(next);
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	} catch (NumberFormatException e) {
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected an integer");
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and converts it to an unsigned 32 bit
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * integer.
420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as an unsigned 32 bit integer.
421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not an unsigned 32
422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bit integer.
423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic long
426d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetUInt32() throws IOException {
427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	long l = getLong();
428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (l < 0 || l > 0xFFFFFFFFL)
429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected an 32 bit unsigned integer");
430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return l;
431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and converts it to an unsigned 16 bit
435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * integer.
436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as an unsigned 16 bit integer.
437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not an unsigned 16
438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bit integer.
439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic int
442d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetUInt16() throws IOException {
443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	long l = getLong();
444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (l < 0 || l > 0xFFFFL)
445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected an 16 bit unsigned integer");
446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return (int) l;
447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and converts it to an unsigned 8 bit
451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * integer.
452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as an unsigned 8 bit integer.
453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not an unsigned 8
454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bit integer.
455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic int
458d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetUInt8() throws IOException {
459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	long l = getLong();
460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (l < 0 || l > 0xFFL)
461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected an 8 bit unsigned integer");
462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return (int) l;
463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and parses it as a TTL.
467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as an unsigned 32 bit integer.
468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was not valid.
469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see TTL
471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic long
473d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetTTL() throws IOException {
474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String next = _getIdentifier("a TTL value");
475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return TTL.parseTTL(next);
477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	catch (NumberFormatException e) {
479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected a TTL value");
480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and parses it as if it were a TTL.
485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as an unsigned 32 bit integer.
486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was not valid.
487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see TTL
489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic long
491d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetTTLLike() throws IOException {
492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String next = _getIdentifier("a TTL-like value");
493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return TTL.parse(next, false);
495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	catch (NumberFormatException e) {
497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected a TTL-like value");
498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and converts it to a name.
503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param origin The origin to append to relative names.
504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as a name.
505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not a valid name.
506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws RelativeNameException The parsed name was relative, even with the
508d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * origin.
509d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see Name
510d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
511d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Name
512d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetName(Name origin) throws IOException {
513d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String next = _getIdentifier("a name");
514d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
515d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		Name name = Name.fromString(next, origin);
516d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (!name.isAbsolute())
517d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw new RelativeNameException(name);
518d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return name;
519d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
520d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	catch (TextParseException e) {
521d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception(e.getMessage());
522d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
523d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
524d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
525d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
526d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and converts it to an IP Address.
527d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param family The address family.
528d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The next token in the stream, as an InetAddress
529d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not a valid address.
530d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
531d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see Address
532d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
533d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic InetAddress
534d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetAddress(int family) throws IOException {
535d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String next = _getIdentifier("an address");
536d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
537d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return Address.getByAddress(next, family);
538d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
539d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	catch (UnknownHostException e) {
540d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception(e.getMessage());
541d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
542d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
543d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
544d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
545d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer, which must be an EOL or EOF.
546d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid or not an EOL or EOF token.
547d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
548d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
549d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
550d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetEOL() throws IOException {
551d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Token next = get();
552d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (next.type != EOL && next.type != EOF) {
553d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("expected EOL or EOF");
554d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
555d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
556d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
557d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
558d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a concatenation of the remaining strings from a Tokenizer.
559d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
560d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate String
561d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenremainingStrings() throws IOException {
562d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        StringBuffer buffer = null;
563d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        while (true) {
564d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                Tokenizer.Token t = get();
565d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (!t.isString())
566d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        break;
567d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (buffer == null)
568d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        buffer = new StringBuffer();
569d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                buffer.append(t.value);
570d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
571d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        unget();
572d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (buffer == null)
573d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return null;
574d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return buffer.toString();
575d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
576d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
577d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
578d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the remaining string tokens until an EOL/EOF is seen, concatenates
579d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * them together, and converts the base64 encoded data to a byte array.
580d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param required If true, an exception will be thrown if no strings remain;
581d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * otherwise null be be returned.
582d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The byte array containing the decoded strings, or null if there
583d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * were no strings to decode.
584d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
585d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
586d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
587d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic byte []
588d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetBase64(boolean required) throws IOException {
589d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String s = remainingStrings();
590d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (s == null) {
591d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (required)
592d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw exception("expected base64 encoded string");
593d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		else
594d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return null;
595d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
596d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	byte [] array = base64.fromString(s);
597d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (array == null)
598d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("invalid base64 encoding");
599d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return array;
600d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
601d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
602d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
603d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the remaining string tokens until an EOL/EOF is seen, concatenates
604d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * them together, and converts the base64 encoded data to a byte array.
605d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The byte array containing the decoded strings, or null if there
606d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * were no strings to decode.
607d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
608d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
609d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
610d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic byte []
611d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetBase64() throws IOException {
612d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return getBase64(false);
613d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
614d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
615d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
616d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the remaining string tokens until an EOL/EOF is seen, concatenates
617d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * them together, and converts the hex encoded data to a byte array.
618d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param required If true, an exception will be thrown if no strings remain;
619d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * otherwise null be be returned.
620d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The byte array containing the decoded strings, or null if there
621d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * were no strings to decode.
622d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
623d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
624d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
625d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic byte []
626d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetHex(boolean required) throws IOException {
627d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String s = remainingStrings();
628d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (s == null) {
629d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (required)
630d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw exception("expected hex encoded string");
631d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		else
632d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return null;
633d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
634d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	byte [] array = base16.fromString(s);
635d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (array == null)
636d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("invalid hex encoding");
637d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return array;
638d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
639d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
640d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
641d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the remaining string tokens until an EOL/EOF is seen, concatenates
642d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * them together, and converts the hex encoded data to a byte array.
643d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The byte array containing the decoded strings, or null if there
644d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * were no strings to decode.
645d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
646d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
647d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
648d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic byte []
649d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetHex() throws IOException {
650d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return getHex(false);
651d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
652d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
653d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
654d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and decodes it as hex.
655d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The byte array containing the decoded string.
656d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
657d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
658d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
659d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic byte []
660d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetHexString() throws IOException {
661d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String next = _getIdentifier("a hex string");
662d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	byte [] array = base16.fromString(next);
663d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (array == null)
664d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("invalid hex encoding");
665d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return array;
666d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
667d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
668d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
669d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the next token from a tokenizer and decodes it as base32.
670d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param b32 The base32 context to decode with.
671d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The byte array containing the decoded string.
672d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws TextParseException The input was invalid.
673d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An I/O error occurred.
674d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
675d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic byte []
676d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetBase32String(base32 b32) throws IOException {
677d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String next = _getIdentifier("a base32 string");
678d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	byte [] array = b32.fromString(next);
679d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (array == null)
680d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw exception("invalid base32 encoding");
681d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return array;
682d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
683d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
684d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
685d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates an exception which includes the current state in the error message
686d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param s The error message to include.
687d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The exception to be thrown
688d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
689d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic TextParseException
690d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenexception(String s) {
691d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return new TokenizerException(filename, line, s);
692d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
693d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
694d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
695d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Closes any files opened by this tokenizer.
696d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
697d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
698d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenclose() {
699d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (wantClose) {
700d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		try {
701d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			is.close();
702d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
703d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		catch (IOException e) {
704d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
705d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
706d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
707d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
708d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprotected void
709d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenfinalize() {
710d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	close();
711d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
712d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
713d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
714