001: /*
002: * @(#)HeaderParser.java 1.16 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.net.www;
029:
030: import java.util.Iterator;
031:
032: /* This is useful for parsing multi-part HTTP/RFC822 headers
033: * sensibly:
034: * From a String like: 'timeout=15, max=5'
035: * create an array of Strings:
036: * { {"timeout", "15"},
037: * {"max", "5"}
038: * }
039: * From one like: 'Basic Realm="FuzzFace" Foo="Biz Bar Baz"'
040: * create one like (no quotes in literal):
041: * { {"basic", null},
042: * {"realm", "FuzzFace"}
043: * {"foo", "Biz Bar Baz"}
044: * }
045: * keys are converted to lower case, vals are left as is....
046: *
047: * @version 1.9, 11/09/00
048: * @author Dave Brown
049: */
050:
051: public class HeaderParser {
052:
053: /* table of key/val pairs */
054: String raw;
055: String[][] tab;
056: int nkeys;
057: int asize = 10; // initial size of array is 10
058:
059: public HeaderParser(String raw) {
060: this .raw = raw;
061: tab = new String[asize][2];
062: parse();
063: }
064:
065: private HeaderParser() {
066: }
067:
068: /**
069: * create a new HeaderParser from this, whose keys (and corresponding values)
070: * range from "start" to "end-1"
071: */
072: public HeaderParser subsequence(int start, int end) {
073: if (start == 0 && end == nkeys) {
074: return this ;
075: }
076: if (start < 0 || start >= end || end > nkeys)
077: throw new IllegalArgumentException("invalid start or end");
078: HeaderParser n = new HeaderParser();
079: n.tab = new String[asize][2];
080: n.asize = asize;
081: System.arraycopy(tab, start, n.tab, 0, (end - start));
082: n.nkeys = (end - start);
083: return n;
084: }
085:
086: private void parse() {
087:
088: if (raw != null) {
089: raw = raw.trim();
090: char[] ca = raw.toCharArray();
091: int beg = 0, end = 0, i = 0;
092: boolean inKey = true;
093: boolean inQuote = false;
094: int len = ca.length;
095: while (end < len) {
096: char c = ca[end];
097: if ((c == '=') && !inQuote) { // end of a key
098: tab[i][0] = new String(ca, beg, end - beg)
099: .toLowerCase();
100: inKey = false;
101: end++;
102: beg = end;
103: } else if (c == '\"') {
104: if (inQuote) {
105: tab[i++][1] = new String(ca, beg, end - beg);
106: inQuote = false;
107: do {
108: end++;
109: } while (end < len
110: && (ca[end] == ' ' || ca[end] == ','));
111: inKey = true;
112: beg = end;
113: } else {
114: inQuote = true;
115: end++;
116: beg = end;
117: }
118: } else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
119: if (inQuote) {
120: end++;
121: continue;
122: } else if (inKey) {
123: tab[i++][0] = (new String(ca, beg, end - beg))
124: .toLowerCase();
125: } else {
126: tab[i++][1] = (new String(ca, beg, end - beg));
127: }
128: while (end < len
129: && (ca[end] == ' ' || ca[end] == ',')) {
130: end++;
131: }
132: inKey = true;
133: beg = end;
134: } else {
135: end++;
136: }
137: if (i == asize) {
138: asize = asize * 2;
139: String[][] ntab = new String[asize][2];
140: System.arraycopy(tab, 0, ntab, 0, tab.length);
141: tab = ntab;
142: }
143: }
144: // get last key/val, if any
145: if (--end > beg) {
146: if (!inKey) {
147: if (ca[end] == '\"') {
148: tab[i++][1] = (new String(ca, beg, end - beg));
149: } else {
150: tab[i++][1] = (new String(ca, beg, end - beg
151: + 1));
152: }
153: } else {
154: tab[i++][0] = (new String(ca, beg, end - beg + 1))
155: .toLowerCase();
156: }
157: } else if (end == beg) {
158: if (!inKey) {
159: if (ca[end] == '\"') {
160: tab[i++][1] = String.valueOf(ca[end - 1]);
161: } else {
162: tab[i++][1] = String.valueOf(ca[end]);
163: }
164: } else {
165: tab[i++][0] = String.valueOf(ca[end]).toLowerCase();
166: }
167: }
168: nkeys = i;
169: }
170:
171: }
172:
173: public String findKey(int i) {
174: if (i < 0 || i > asize)
175: return null;
176: return tab[i][0];
177: }
178:
179: public String findValue(int i) {
180: if (i < 0 || i > asize)
181: return null;
182: return tab[i][1];
183: }
184:
185: public String findValue(String key) {
186: return findValue(key, null);
187: }
188:
189: public String findValue(String k, String Default) {
190: if (k == null)
191: return Default;
192: k = k.toLowerCase();
193: for (int i = 0; i < asize; ++i) {
194: if (tab[i][0] == null) {
195: return Default;
196: } else if (k.equals(tab[i][0])) {
197: return tab[i][1];
198: }
199: }
200: return Default;
201: }
202:
203: class ParserIterator implements Iterator {
204: int index;
205: boolean returnsValue; // or key
206:
207: ParserIterator(boolean returnValue) {
208: returnsValue = returnValue;
209: }
210:
211: public boolean hasNext() {
212: return index < nkeys;
213: }
214:
215: public Object next() {
216: return tab[index++][returnsValue ? 1 : 0];
217: }
218:
219: public void remove() {
220: throw new UnsupportedOperationException(
221: "remove not supported");
222: }
223: }
224:
225: public Iterator keys() {
226: return new ParserIterator(false);
227: }
228:
229: public Iterator values() {
230: return new ParserIterator(true);
231: }
232:
233: public String toString() {
234: Iterator k = keys();
235: StringBuffer sbuf = new StringBuffer();
236: sbuf.append("{size=" + asize + " nkeys=" + nkeys + " ");
237: for (int i = 0; k.hasNext(); i++) {
238: String key = (String) k.next();
239: String val = findValue(i);
240: if (val != null && "".equals(val)) {
241: val = null;
242: }
243: sbuf.append(" {" + key + (val == null ? "" : "," + val)
244: + "}");
245: if (k.hasNext()) {
246: sbuf.append(",");
247: }
248: }
249: sbuf.append(" }");
250: return new String(sbuf);
251: }
252:
253: public int findInt(String k, int Default) {
254: try {
255: return Integer.parseInt(findValue(k, String
256: .valueOf(Default)));
257: } catch (Throwable t) {
258: return Default;
259: }
260: }
261: /*
262: public static void main(String[] a) throws Exception {
263: System.out.print("enter line to parse> ");
264: System.out.flush();
265: DataInputStream dis = new DataInputStream(System.in);
266: String line = dis.readLine();
267: HeaderParser p = new HeaderParser(line);
268: for (int i = 0; i < asize; ++i) {
269: if (p.findKey(i) == null) break;
270: String v = p.findValue(i);
271: System.out.println(i + ") " +p.findKey(i) + "="+v);
272: }
273: System.out.println("Done!");
274:
275: }
276: */
277: }
|