Sync with latest bnd code for testing purposes

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1354104 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/lib/properties/PropertiesLineReader.java b/bundleplugin/src/main/java/aQute/lib/properties/PropertiesLineReader.java
new file mode 100644
index 0000000..c3ea14b
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/lib/properties/PropertiesLineReader.java
@@ -0,0 +1,125 @@
+package aQute.lib.properties;
+
+import static aQute.lib.properties.LineType.*;
+
+public class PropertiesLineReader {
+
+	private final IDocument	document;
+	private final int		lineCount;
+
+	private int				lineNum		= 0;
+
+	private IRegion			lastRegion	= null;
+	private String			lastKey		= null;
+	private String			lastValue	= null;
+
+	public PropertiesLineReader(IDocument document) {
+		this.document = document;
+		this.lineCount = document.getNumberOfLines();
+	}
+
+	public PropertiesLineReader(String data) {
+		this(new Document(data));
+	}
+
+	public LineType next() throws Exception {
+		int index = 0;
+		char[] chars = null;
+
+		StringBuilder keyData = new StringBuilder();
+		StringBuilder valueData = new StringBuilder();
+		StringBuilder currentBuffer = keyData;
+
+		boolean started = false;
+
+		mainLoop: while (true) {
+			if (chars == null)
+				chars = grabLine(false);
+			if (chars == null)
+				return eof;
+
+			if (index >= chars.length)
+				break;
+
+			char c = chars[index];
+			if (c == '\\') {
+				index++;
+				if (index == chars.length) {
+					chars = grabLine(true);
+					index = 0;
+					if (chars == null || chars.length == 0)
+						break; // The last line ended with a backslash
+				}
+				currentBuffer.append(chars[index]);
+				index++;
+				continue mainLoop;
+			}
+
+			if (c == '=' || c == ':')
+				currentBuffer = valueData;
+
+			if (!started && (c == '#' || c == '!'))
+				return comment;
+
+			if (Character.isWhitespace(c)) {
+				if (started) {
+					// whitespace ends the key
+					currentBuffer = valueData;
+				}
+			} else {
+				started = true;
+				currentBuffer.append(c);
+			}
+
+			index++;
+		}
+
+		if (!started)
+			return blank;
+
+		lastKey = keyData.toString();
+		return entry;
+	}
+
+	private char[] grabLine(boolean continued) throws BadLocationException {
+		if (lineNum >= lineCount) {
+			lastRegion = null;
+			return null;
+		}
+
+		IRegion lineInfo = document.getLineInformation(lineNum);
+		char[] chars = document.get(lineInfo.getOffset(), lineInfo.getLength()).toCharArray();
+
+		if (continued) {
+			int length = lastRegion.getLength();
+			length += document.getLineDelimiter(lineNum - 1).length();
+			length += lineInfo.getLength();
+			lastRegion = new Region(lastRegion.getOffset(), length);
+		} else {
+			lastRegion = lineInfo;
+		}
+
+		lineNum++;
+		return chars;
+	}
+
+	public IRegion region() {
+		if (lastRegion == null)
+			throw new IllegalStateException("Last region not available: either before start or after end of document.");
+		return lastRegion;
+	}
+
+	public String key() {
+		if (lastKey == null)
+			throw new IllegalStateException(
+					"Last key not available: either before state or after end of document, or last line type was not 'entry'.");
+		return lastKey;
+	}
+
+	public String value() {
+		if (lastValue == null)
+			throw new IllegalStateException(
+					"Last value not available: either before state or after end of document, or last line type was not 'entry'.");
+		return lastValue;
+	}
+}