001: /*
002: *
003: *
004: * Copyright 1990-2007 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: package gov.nist.siplite.parser;
028:
029: import java.util.Stack;
030: import gov.nist.core.*;
031: import gov.nist.siplite.header.*;
032:
033: /**
034: * Parser for content type header.
035: *
036: */
037: public class ExtensionParser extends ParametersParser {
038: /** Default constructor. */
039: protected ExtensionParser() {
040: }
041:
042: /**
043: * Constructor with header value.
044: * @param value full header value respresented as a string
045: */
046: public ExtensionParser(String value) {
047: super (value);
048: }
049:
050: /**
051: * Constructor with initial lexer engine.
052: * @param lexer initial lexer engine
053: */
054: protected ExtensionParser(Lexer lexer) {
055: super (lexer);
056: }
057:
058: /**
059: * Searches a given string for a given character and returns its index.
060: * This function should be used instead of String.indexOf(char) to handle
061: * the cases like <br>
062: * SomeHeader: "Token1; Token2" <sip:something;sip_param>param=value
063: * <br>
064: * It will return an index of the ';' located before the "param=value".
065: * IMPL_NOTE: optimize and think about moving it to Lexer.
066: * @param buffer a string that will be searched for the delimiter
067: * @param delimiter a character to look for
068: * @return an index of the delimiter of -1 if it was not found
069: */
070: private int getDelimiterIndex(String buffer, char delimiter) {
071: Stack stack = new Stack();
072: char ch, top;
073:
074: for (int i = 0; i < buffer.length(); i++) {
075: ch = buffer.charAt(i);
076:
077: if (!stack.empty()) {
078: top = ((Character) stack.peek()).charValue();
079: } else {
080: top = '\0';
081: }
082:
083: if (ch == '<') {
084: if (top != '"') {
085: stack.push(new Character(ch));
086: }
087: continue;
088: }
089:
090: if (ch == '>') {
091: if (top == '<') {
092: stack.pop();
093: }
094: continue;
095: }
096:
097: if (ch == '"') {
098: if (top == '"') {
099: stack.pop();
100: } else {
101: stack.push(new Character(ch));
102: }
103: continue;
104: }
105:
106: if (!stack.empty()) {
107: continue;
108: }
109:
110: if (ch == delimiter) {
111: return i;
112: }
113: }
114:
115: return -1;
116: }
117:
118: /**
119: * Invokes parser for extension header field.
120: * IMPL_NOTE: optimize it (maybe use ParserCore.nameValue()?).
121: * @return the parsed extension header
122: * @throws ParseException if a parsing error occurs
123: */
124: public Header parse() throws ParseException {
125: String name = lexer.getNextToken(':');
126: lexer.consume(1);
127: lexer.SPorHT();
128: String bodyWithParam = StringTokenizer.convertNewLines(lexer
129: .getRest().trim());
130: char colonDelimiter = ';';
131: int index = getDelimiterIndex(bodyWithParam, colonDelimiter);
132:
133: if (index == -1) {
134: // no parameters were specified
135: // String body = lexer.getLine().trim();
136: ExtensionHeader retval = new ExtensionHeader(name,
137: bodyWithParam, bodyWithParam);
138: return retval;
139: } else {
140: int currPos = lexer.getPtr();
141: String body = StringTokenizer.convertNewLines(lexer
142: .getBuffer().substring(currPos, currPos + index)
143: .trim());
144: lexer.consume(index + 1);
145: lexer.SPorHT();
146:
147: ExtensionHeader retval = new ExtensionHeader(name,
148: bodyWithParam, body);
149:
150: String paramName, paramVal;
151: boolean headerEnd = false;
152: int eqIndex, semicolonIndex;
153:
154: while (!headerEnd) {
155: paramName = lexer.peekLine().trim();
156:
157: eqIndex = paramName.indexOf('=');
158: semicolonIndex = paramName.indexOf(colonDelimiter);
159:
160: if ((eqIndex != -1)
161: && (semicolonIndex > eqIndex || semicolonIndex == -1)) {
162: // parameter with a value
163: paramName = lexer.getString('=');
164:
165: // take the rest of the line
166: paramVal = lexer.peekLine().trim();
167:
168: // IMPL_NOTE: remove !!!
169: // System.out.println("*** Rest is '" + paramVal + "'");
170:
171: if (paramVal.indexOf(colonDelimiter) != -1) {
172: paramVal = lexer.getString(colonDelimiter);
173: } else {
174: paramVal = lexer.getLine().trim();
175: headerEnd = true;
176: }
177: } else {
178: if (semicolonIndex != -1) {
179: // parameter without a value
180: paramName = lexer.getString(colonDelimiter);
181: } else {
182: // the last parameter without a value
183: paramName = lexer.getLine().trim();
184: headerEnd = true;
185: }
186:
187: paramVal = "";
188: }
189:
190: paramName = paramName.trim();
191: paramVal = paramVal.trim();
192:
193: // IMPL_NOTE: remove !!!
194: // System.out.println("*** paramName = " + paramName);
195:
196: // IMPL_NOTE: remove !!!
197: // System.out.println(">>> Adding '" +
198: // paramName + "' = '" + paramVal + "'");
199:
200: // The following toLowerCase() call is required because
201: // some 'known' headers (like Accept-Language) haven't
202: // corresponding implementation classes, but
203: // ExtensionHeader class is used to represent them.
204: //
205: // So, here we have to care about 'known' parameters for
206: // the mentioned headers. For example, a parameter 'q'
207: // must be case-insensitive.
208: paramName = paramName.toLowerCase();
209:
210: // Validate parameter's name and value
211: if (!Lexer.isValidName(paramName)) {
212: throw new ParseException(
213: "Invalid parameter's name.", 0);
214: }
215:
216: if (!Lexer.isValidParameterValue(paramVal)) {
217: throw new ParseException(
218: "Invalid parameter's value.", 0);
219: }
220:
221: if (retval.getParameter(paramName) != null) {
222: throw new ParseException("Duplicated parameter: "
223: + paramName, 0);
224: }
225:
226: retval.setParameter(paramName, paramVal);
227: } // end while()
228:
229: return retval;
230: }
231: }
232: }
|