Use local copy of latest bndlib code for pre-release testing purposes

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1347815 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/libg/header/Attrs.java b/bundleplugin/src/main/java/aQute/libg/header/Attrs.java
new file mode 100644
index 0000000..d11b6d1
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/header/Attrs.java
@@ -0,0 +1,295 @@
+package aQute.libg.header;
+
+import java.util.*;
+import java.util.regex.*;
+
+import aQute.lib.collections.*;
+import aQute.libg.version.*;
+
+public class Attrs implements Map<String, String> {
+	public enum Type {
+		STRING(null), LONG(null), VERSION(null), DOUBLE(null), STRINGS(STRING), LONGS(LONG), VERSIONS(VERSION), DOUBLES(DOUBLE);
+
+		Type	sub;
+
+		Type(Type sub) {
+			this.sub = sub;
+		}
+
+	}
+
+	/**
+	 * <pre>
+	 * Provide-Capability ::= capability ::=
+	 * name-space ::= typed-attr ::= type ::= scalar ::=
+	 * capability ( ',' capability )*
+	 * name-space
+	 *     ( ’;’ directive | typed-attr )*
+	 * symbolic-name
+	 * extended ( ’:’ type ) ’=’ argument
+	 * scalar | list
+	 * ’String’ | ’Version’ | ’Long’
+	 * list ::=
+	 * ’List<’ scalar ’>’
+	 * </pre>
+	 */
+	static String					EXTENDED	= "[\\-0-9a-zA-Z\\._]+";
+	static String					SCALAR		= "String|Version|Long|Double";
+	static String					LIST		= "List\\s*<\\s*(" + SCALAR + ")\\s*>";
+	public static final Pattern		TYPED		= Pattern.compile("\\s*(" + EXTENDED + ")\\s*:\\s*("+ SCALAR + "|" + LIST + ")\\s*");
+
+	private LinkedHashMap<String, String>	map;
+	private Map<String, Type>		types;
+	static Map<String, String>		EMPTY		= Collections.emptyMap();
+
+	public Attrs(Attrs... attrs) {
+		for (Attrs a : attrs) {
+			if (a != null) {
+				putAll(a);
+			}
+		}
+	}
+
+	public void clear() {
+		map.clear();
+	}
+
+	public boolean containsKey(String name) {
+		if (map == null)
+			return false;
+
+		return map.containsKey(name);
+	}
+
+	@SuppressWarnings("cast")
+	@Deprecated public boolean containsKey(Object name) {
+		assert name instanceof String;
+		if (map == null)
+			return false;
+
+		return map.containsKey((String) name);
+	}
+
+	public boolean containsValue(String value) {
+		if (map == null)
+			return false;
+
+		return map.containsValue(value);
+	}
+
+	@SuppressWarnings("cast")
+	@Deprecated public boolean containsValue(Object value) {
+		assert value instanceof String;
+		if (map == null)
+			return false;
+
+		return map.containsValue((String) value);
+	}
+
+	public Set<java.util.Map.Entry<String, String>> entrySet() {
+		if (map == null)
+			return EMPTY.entrySet();
+
+		return map.entrySet();
+	}
+
+	@SuppressWarnings("cast")
+	@Deprecated public String get(Object key) {
+		assert key instanceof String;
+		if (map == null)
+			return null;
+
+		return map.get((String) key);
+	}
+
+	public String get(String key) {
+		if (map == null)
+			return null;
+
+		return map.get(key);
+	}
+
+	public String get(String key, String deflt) {
+		String s = get(key);
+		if (s == null)
+			return deflt;
+		return s;
+	}
+
+	public boolean isEmpty() {
+		return map == null || map.isEmpty();
+	}
+
+	public Set<String> keySet() {
+		if (map == null)
+			return EMPTY.keySet();
+
+		return map.keySet();
+	}
+
+	public String put(String key, String value) {
+		if (map == null)
+			map = new LinkedHashMap<String, String>();
+
+		Matcher m = TYPED.matcher(key);
+		if (m.matches()) {
+			key = m.group(1);
+			String type = m.group(2);
+			Type t = Type.STRING;
+
+			if ( type.startsWith("List")) {
+				type = m.group(3);
+				if ( "String".equals(type))
+					t = Type.STRINGS;
+				else if ( "Long".equals(type))
+					t = Type.LONGS;
+				else if ( "Double".equals(type))
+					t = Type.DOUBLES;
+				else if ( "Version".equals(type))
+					t = Type.VERSIONS;				
+			} else {
+				if ( "String".equals(type))
+					t = Type.STRING;
+				else if ( "Long".equals(type))
+					t = Type.LONG;
+				else if ( "Double".equals(type))
+					t = Type.DOUBLE;
+				else if ( "Version".equals(type))
+					t = Type.VERSION;
+			}
+			if (types == null)
+				types = new LinkedHashMap<String, Type>();
+			types.put(key, t);
+
+			// TODO verify value?
+		}
+
+		return map.put(key, value);
+	}
+
+	public Type getType(String key) {
+		if (types == null)
+			return Type.STRING;
+		Type t = types.get(key);
+		if (t == null)
+			return Type.STRING;
+		return t;
+	}
+
+	public void putAll(Map<? extends String, ? extends String> map) {
+		for (Map.Entry<? extends String, ? extends String> e : map.entrySet())
+			put(e.getKey(), e.getValue());
+	}
+
+	@SuppressWarnings("cast")
+	@Deprecated public String remove(Object var0) {
+		assert var0 instanceof String;
+		if (map == null)
+			return null;
+
+		return map.remove((String) var0);
+	}
+
+	public String remove(String var0) {
+		if (map == null)
+			return null;
+		return map.remove(var0);
+	}
+
+	public int size() {
+		if (map == null)
+			return 0;
+		return map.size();
+	}
+
+	public Collection<String> values() {
+		if (map == null)
+			return EMPTY.values();
+
+		return map.values();
+	}
+
+	public String getVersion() {
+		return get("version");
+	}
+
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		append(sb);
+		return sb.toString();
+	}
+
+	public void append(StringBuilder sb) {
+		String del = "";
+		for (Map.Entry<String, String> e : entrySet()) {
+			sb.append(del);
+			sb.append(e.getKey());
+			sb.append("=");
+			sb.append(e.getValue());
+			del = ";";
+		}
+	}
+
+	@Deprecated public boolean equals(Object other) {
+		return super.equals(other);
+	}
+
+	@Deprecated public int hashCode() {
+		return super.hashCode();
+	}
+
+	public boolean isEqual(Attrs o) {
+		if (this == o)
+			return true;
+
+		Attrs other = o;
+
+		if (size() != other.size())
+			return false;
+
+		if (isEmpty())
+			return true;
+
+		SortedList<String> l = new SortedList<String>(keySet());
+		SortedList<String> lo = new SortedList<String>(other.keySet());
+		if (!l.isEqual(lo))
+			return false;
+
+		for (String key : keySet()) {
+			if (!get(key).equals(other.get(key)))
+				return false;
+		}
+		return true;
+
+	}
+
+	public Object getTyped(String adname) {
+		String s = get(adname);
+		if (s == null)
+			return null;
+
+		Type t = getType(adname);
+		return convert(t, s);
+	}
+
+	private Object convert(Type t, String s) {
+		if (t.sub == null) {
+			switch (t) {
+			case STRING:
+				return s;
+			case LONG:
+				return Long.parseLong(s.trim());
+			case VERSION:
+				return Version.parseVersion(s);
+			}
+			return null;
+		}
+		List<Object> list = new ArrayList<Object>();
+		String split[] = s.split("\\s*\\(\\?!\\),\\s*");
+		for (String p : split) {
+			p = p.replaceAll("\\\\", "");
+			list.add(convert(t.sub, p));
+		}
+		return list;
+	}
+}