| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.axiom.mime; |
| |
| import java.text.ParseException; |
| |
| final class ContentTypeTokenizer { |
| // Note: normally only ' ' and '\t' can appear in unfolded header values, but we accept parsing folded values |
| private static final String whitespace = " \t\n\r"; |
| |
| private static final String tspecials = "()<>@,;:\\\"/[]?="; |
| |
| private final String s; |
| private int index; |
| |
| public ContentTypeTokenizer(String s) { |
| this.s = s; |
| } |
| |
| private void skipWhiteSpace() { |
| for (int len = s.length(); index < len && whitespace.indexOf(s.charAt(index)) != -1; index++) { |
| // Just loop |
| } |
| } |
| |
| String expectToken() throws ParseException { |
| skipWhiteSpace(); |
| int begin = index; |
| for (int len = s.length(); index < len && tspecials.indexOf(s.charAt(index)) == -1; index++) { |
| // Just loop |
| } |
| int end = index; |
| for (; end > begin && whitespace.indexOf(s.charAt(end-1)) != -1; end--) { |
| // Just loop |
| } |
| if (begin == end) { |
| if (index == s.length()) { |
| return null; |
| } else { |
| throw new ParseException("Expected token, but found '" + s.charAt(index) + "'", index); |
| } |
| } else { |
| return s.substring(begin, end); |
| } |
| } |
| |
| String requireToken() throws ParseException { |
| String token = expectToken(); |
| if (token == null) { |
| throw new ParseException("Token expected", index); |
| } |
| return token; |
| } |
| |
| String requireTokenOrQuotedString() throws ParseException { |
| skipWhiteSpace(); |
| int len = s.length(); |
| if (index < len) { |
| if (s.charAt(index) == '\"') { |
| StringBuffer sb = new StringBuffer(); |
| index++; |
| for (; index < len; index++) { |
| char c = s.charAt(index); |
| if (c == '\\') { |
| index++; |
| if (index == len) { |
| throw new ParseException("Expected more input after escape character", index); |
| } |
| sb.append(s.charAt(index)); |
| } else if (c == '\"') { |
| break; |
| } else { |
| sb.append(c); |
| } |
| } |
| if (index == len) { |
| throw new ParseException("Unclosed quoted string", index); |
| } |
| // If we get here, then the current character is a quote; skip it |
| index++; |
| skipWhiteSpace(); |
| return sb.toString(); |
| } else { |
| return requireToken(); |
| } |
| } else { |
| throw new ParseException("Unexpected end of string; expected token or quoted string", index); |
| } |
| } |
| |
| boolean expect(char c) throws ParseException { |
| if (index == s.length()) { |
| return false; |
| } else { |
| char actual = s.charAt(index); |
| if (actual == c) { |
| index++; |
| return true; |
| } else { |
| throw new ParseException("Expected '" + c + "' instead of '" + actual + "'", index); |
| } |
| } |
| } |
| |
| void require(char c) throws ParseException { |
| if (!expect(c)) { |
| throw new ParseException("Unexpected end of string; expected '" + c + "'", index); |
| } |
| } |
| |
| void requireEndOfString() throws ParseException { |
| if (index != s.length()) { |
| throw new ParseException("Unexpected character '" + s.charAt(index) + "'; expected end of string", index); |
| } |
| } |
| } |