Rewrite code to parse the standard OSGi manifest header (FELIX-2973).
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1167139 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
index 4ebd09f..26d1ddd 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
@@ -19,7 +19,6 @@
package org.apache.felix.framework.util.manifestparser;
import java.util.*;
-import java.util.ArrayList;
import java.util.Map.Entry;
import org.apache.felix.framework.BundleRevisionImpl;
@@ -1538,7 +1537,7 @@
public static void main(String[] headers)
{
String header = headers[0];
-
+
if (header != null)
{
if (header.length() == 0)
@@ -1546,8 +1545,8 @@
throw new IllegalArgumentException(
"A header cannot be an empty string.");
}
-
List<ParsedHeaderClause> clauses = parseStandardHeader(header);
+
for (ParsedHeaderClause clause : clauses)
{
System.out.println("PATHS " + clause.m_paths);
@@ -1555,268 +1554,160 @@
System.out.println(" ATTRS " + clause.m_attrs);
System.out.println(" TYPES " + clause.m_types);
}
+
}
-
-// return clauses;
}
-
- private static List<ParsedHeaderClause> parseStandardHeader(String header)
+
+ private static final char EOF = (char) -1;
+
+ private static char charAt(int pos, String headers, int length)
+ {
+ if (pos >= length)
+ {
+ return EOF;
+ }
+ return headers.charAt(pos);
+ }
+
+ private static final int CLAUSE_START = 0;
+ private static final int PARAMETER_START = 1;
+ private static final int KEY = 2;
+ private static final int DIRECTIVE_OR_TYPEDATTRIBUTE = 4;
+ private static final int ARGUMENT = 8;
+ private static final int VALUE = 16;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static List<ParsedHeaderClause> parseStandardHeader(String header)
{
List<ParsedHeaderClause> clauses = new ArrayList<ParsedHeaderClause>();
- if (header != null)
+ if (header == null)
{
- int[] startIdx = new int[1];
- startIdx[0] = 0;
- for (int i = 0; i < header.length(); i++)
+ return clauses;
+ }
+ ParsedHeaderClause clause = null;
+ String key = null;
+ Map targetMap = null;
+ int state = CLAUSE_START;
+ int currentPosition = 0;
+ int startPosition = 0;
+ int length = header.length();
+ boolean quoted = false;
+ boolean escaped = false;
+
+ char currentChar = EOF;
+ do
+ {
+ currentChar = charAt(currentPosition, header, length);
+ switch (state)
{
- clauses.add(parseClause(startIdx, header));
- i = startIdx[0];
- }
+ case CLAUSE_START:
+ clause = new ParsedHeaderClause(
+ new ArrayList<String>(),
+ new HashMap<String, String>(),
+ new HashMap<String, Object>(),
+ new HashMap<String, String>());
+ clauses.add(clause);
+ state = PARAMETER_START;
+ case PARAMETER_START:
+ startPosition = currentPosition;
+ state = KEY;
+ case KEY:
+ switch (currentChar)
+ {
+ case ':':
+ case '=':
+ key = header.substring(startPosition, currentPosition).trim();
+ startPosition = currentPosition + 1;
+ targetMap = clause.m_attrs;
+ state = currentChar == ':' ? DIRECTIVE_OR_TYPEDATTRIBUTE : ARGUMENT;
+ break;
+ case EOF:
+ case ',':
+ case ';':
+ clause.m_paths.add(header.substring(startPosition, currentPosition).trim());
+ state = currentChar == ',' ? CLAUSE_START : PARAMETER_START;
+ break;
+ default:
+ break;
+ }
+ currentPosition++;
+ break;
+ case DIRECTIVE_OR_TYPEDATTRIBUTE:
+ switch(currentChar)
+ {
+ case '=':
+ if (startPosition != currentPosition)
+ {
+ clause.m_types.put(key, header.substring(startPosition, currentPosition).trim());
+ }
+ else
+ {
+ targetMap = clause.m_dirs;
+ }
+ state = ARGUMENT;
+ startPosition = currentPosition + 1;
+ break;
+ default:
+ break;
+ }
+ currentPosition++;
+ break;
+ case ARGUMENT:
+ if (currentChar == '\"')
+ {
+ quoted = true;
+ currentPosition++;
+ }
+ else
+ {
+ quoted = false;
+ }
+ state = VALUE;
+ break;
+ case VALUE:
+ escaped = currentChar == '\\';
+ if (quoted && !escaped && currentChar == '\"')
+ {
+ quoted = false;
+ }
+ else if (!quoted)
+ {
+ String value = null;
+ switch(currentChar)
+ {
+ case EOF:
+ case ';':
+ case ',':
+ value = header.substring(startPosition, currentPosition).trim();
+ if (value.startsWith("\"") && value.endsWith("\""))
+ {
+ value = value.substring(1, value.length() - 1);
+ }
+ if (targetMap.put(key, value) != null)
+ {
+ throw new IllegalArgumentException(
+ "Duplicate '" + key + "' in: " + header);
+ }
+ state = currentChar == ';' ? PARAMETER_START : CLAUSE_START;
+ break;
+ default:
+ break;
+ }
+ }
+ currentPosition++;
+ break;
+ default:
+ break;
+ }
+ } while ( currentChar != EOF);
+
+ if (state > PARAMETER_START)
+ {
+ throw new IllegalArgumentException("Unable to parse header: " + header);
}
return clauses;
}
- private static ParsedHeaderClause parseClause(int[] startIdx, String header)
- {
- ParsedHeaderClause clause = new ParsedHeaderClause(
- new ArrayList<String>(),
- new HashMap<String, String>(),
- new HashMap<String, Object>(),
- new HashMap<String, String>());
- for (int i = startIdx[0]; i < header.length(); i++)
- {
- char c = header.charAt(i);
- if ((c == ':') || (c == '='))
- {
- parseClauseParameters(startIdx, header, clause);
- i = startIdx[0];
- break;
- }
- else if ((c == ';') || (c == ',') || (i == (header.length() - 1)))
- {
- String path;
- if (i == (header.length() - 1))
- {
- path = header.substring(startIdx[0], header.length());
- }
- else
- {
- path = header.substring(startIdx[0], i);
- }
- clause.m_paths.add(path.trim());
- startIdx[0] = i + 1;
- if (c == ',')
- {
- break;
- }
- }
- }
- return clause;
- }
-
- private static void parseClauseParameters(
- int[] startIdx, String header, ParsedHeaderClause clause)
- {
- for (int i = startIdx[0]; i < header.length(); i++)
- {
- char c = header.charAt(i);
- if ((c == ':') && (header.charAt(i + 1) == '='))
- {
- parseClauseDirective(startIdx, header, clause);
- i = startIdx[0];
- }
- else if ((c == ':') || (c == '='))
- {
- parseClauseAttribute(startIdx, header, clause);
- i = startIdx[0];
- }
- else if (c == ',')
- {
- startIdx[0] = i + 1;
- break;
- }
- }
- }
-
- private static void parseClauseDirective(
- int[] startIdx, String header, ParsedHeaderClause clause)
- {
- String name = null;
- String value = null;
- boolean isQuoted = false;
- boolean isEscaped = false;
- for (int i = startIdx[0]; i < header.length(); i++)
- {
- char c = header.charAt(i);
- if (!isEscaped && (c == '"'))
- {
- isQuoted = !isQuoted;
- }
-
- if (!isEscaped
- && !isQuoted && (c == ':'))
- {
- name = header.substring(startIdx[0], i);
- startIdx[0] = i + 2;
- }
- else if (!isEscaped
- && !isQuoted && ((c == ';') || (c == ',') || (i == (header.length() - 1))))
- {
- if (i == (header.length() - 1))
- {
- value = header.substring(startIdx[0], header.length());
- }
- else
- {
- value = header.substring(startIdx[0], i);
- }
- if (c == ',')
- {
- startIdx[0] = i - 1;
- }
- else
- {
- startIdx[0] = i + 1;
- }
- break;
- }
-
- isEscaped = (c == '\\');
- }
-
- // Trim whitespace.
- name = name.trim();
- value = value.trim();
-
- // Remove quotes, if value is quoted.
- if (value.startsWith("\"") && value.endsWith("\""))
- {
- value = value.substring(1, value.length() - 1);
- }
-
- // Check for dupes.
- if (clause.m_dirs.get(name) != null)
- {
- throw new IllegalArgumentException(
- "Duplicate directive '" + name + "' in: " + header);
- }
-
- clause.m_dirs.put(name, value);
- }
-
- private static void parseClauseAttribute(
- int[] startIdx, String header, ParsedHeaderClause clause)
- {
- String type = null;
-
- String name = parseClauseAttributeName(startIdx, header);
- char c = header.charAt(startIdx[0]);
- startIdx[0]++;
- if (c == ':')
- {
- type = parseClauseAttributeType(startIdx, header);
- }
-
- String value = parseClauseAttributeValue(startIdx, header);
-
- // Trim whitespace.
- name = name.trim();
- value = value.trim();
- if (type != null)
- {
- type = type.trim();
- }
-
- // Remove quotes, if value is quoted.
- if (value.startsWith("\"") && value.endsWith("\""))
- {
- value = value.substring(1, value.length() - 1);
- }
-
- // Check for dupes.
- if (clause.m_attrs.get(name) != null)
- {
- throw new IllegalArgumentException(
- "Duplicate attribute '" + name + "' in: " + header);
- }
-
- clause.m_attrs.put(name, value);
- if (type != null)
- {
- clause.m_types.put(name, type);
- }
- }
-
- private static String parseClauseAttributeName(int[] startIdx, String header)
- {
- for (int i = startIdx[0]; i < header.length(); i++)
- {
- char c = header.charAt(i);
- if ((c == '=') || (c == ':'))
- {
- String name = header.substring(startIdx[0], i);
- startIdx[0] = i;
- return name;
- }
- }
- return null;
- }
-
- private static String parseClauseAttributeType(int[] startIdx, String header)
- {
- for (int i = startIdx[0]; i < header.length(); i++)
- {
- char c = header.charAt(i);
- if (c == '=')
- {
- String type = header.substring(startIdx[0], i);
- startIdx[0] = i + 1;
- return type;
- }
- }
- return null;
- }
-
- private static String parseClauseAttributeValue(int[] startIdx, String header)
- {
- boolean isQuoted = false;
- boolean isEscaped = false;
- for (int i = startIdx[0]; i < header.length(); i++)
- {
- char c = header.charAt(i);
- if (!isEscaped && (c == '"'))
- {
- isQuoted = !isQuoted;
- }
-
- if (!isEscaped &&
- !isQuoted && ((c == ';') || (c == ',') || (i == (header.length() - 1))))
- {
- String value;
- if (i == (header.length() - 1))
- {
- value = header.substring(startIdx[0], header.length());
- }
- else
- {
- value = header.substring(startIdx[0], i);
- }
- if (c == ',')
- {
- startIdx[0] = i - 1;
- }
- else
- {
- startIdx[0] = i + 1;
- }
- return value;
- }
-
- isEscaped = (c == '\\');
- }
- return null;
- }
-
public static List<String> parseDelimitedString(String value, String delim)
{
return parseDelimitedString(value, delim, true);