Latest
Browser interest query
Test file is called index.html
diff --git a/latest/encoding/TextXMLDecoder.js b/latest/encoding/TextXMLDecoder.js
new file mode 100644
index 0000000..32ac1c5
--- /dev/null
+++ b/latest/encoding/TextXMLDecoder.js
@@ -0,0 +1,225 @@
+
+
+var TextXMLDecoder = function TextXMLDecoder(){
+
+	this.reader = null;
+	
+};
+
+
+exports.TextXMLDecoder = TextXMLDecoder;
+
+
+exports.prototype.initializeDecoding = function(){
+	try {
+		XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        factory.setNamespaceAware(true);
+		_reader = factory.newPullParser();
+		_reader.setInput(_istream, null);
+	} catch (XmlPullParserException e) {
+		throw new ContentDecodingException(e.getMessage(), e);
+	}		
+};
+
+exports.prototype.readStartDocument = function(){
+	try {
+		int event = _reader.getEventType();
+		_reader.next();
+		if (event != XmlPullParser.START_DOCUMENT) {
+			throw new ContentDecodingException("Expected start document, got: " + XmlPullParser.TYPES[event]);
+		}
+	} catch (XmlPullParserException e) {
+		throw new ContentDecodingException(e.getMessage(), e);
+	} catch (IOException e) {
+		throw new ContentDecodingException(e.getMessage(), e);
+	}
+};
+
+public void readEndDocument() throws ContentDecodingException {
+	int event;
+	try {
+		event = _reader.getEventType();
+	} catch (XmlPullParserException e) {
+		throw new ContentDecodingException(e.getMessage(), e);
+	}
+	if (event != XmlPullParser.END_DOCUMENT) {
+		throw new ContentDecodingException("Expected end document, got: " + XmlPullParser.TYPES[event]);
+	}
+};
+
+exports.prototype.readStartElement = function(/*String*/ startTag,
+							TreeMap<String, String> attributes) throws ContentDecodingException {
+
+	int event = readToNextTag(XmlPullParser.START_TAG);
+	if (event != XmlPullParser.START_TAG) {
+		throw new ContentDecodingException("Expected start element, got: " + XmlPullParser.TYPES[event]);
+	}
+	// Use getLocalPart to strip namespaces.
+	// Assumes we are working with a global default namespace of CCN.
+	if (!startTag.equals(_reader.getName())) {
+		// Coming back with namespace decoration doesn't match
+		throw new ContentDecodingException("Expected start element: " + startTag + " got: " + _reader.getName());
+	}	
+	if (null != attributes) {
+		// we might be expecting attributes
+		for (int i=0; i < _reader.getAttributeCount(); ++i) {
+			// may need fancier namespace handling.
+			attributes.put(_reader.getAttributeName(i), _reader.getAttributeValue(i));
+		}
+	}
+	try {
+		_reader.next();
+	} catch (XmlPullParserException e) {
+		throw new ContentDecodingException(e.getMessage());
+	} catch (IOException e) {
+		throw new ContentDecodingException(e.getMessage());
+	}
+}
+
+	public void readStartElement(long startTagLong,
+			TreeMap<String, String> attributes) throws ContentDecodingException {
+		
+		String startTag = tagToString(startTagLong);
+
+		int event = readToNextTag(XmlPullParser.START_TAG);
+		if (event != XmlPullParser.START_TAG) {
+			throw new ContentDecodingException("Expected start element, got: " + XmlPullParser.TYPES[event]);
+		}
+		// Use getLocalPart to strip namespaces.
+		// Assumes we are working with a global default namespace of CCN.
+		if (!startTag.equals(_reader.getName())) {
+			// Coming back with namespace decoration doesn't match
+			throw new ContentDecodingException("Expected start element: " + startTag + " got: " + _reader.getName());
+		}	
+		if (null != attributes) {
+			// we might be expecting attributes
+			for (int i=0; i < _reader.getAttributeCount(); ++i) {
+				// may need fancier namespace handling.
+				attributes.put(_reader.getAttributeName(i), _reader.getAttributeValue(i));
+			}
+		}
+		try {
+			_reader.next();
+		} catch (XmlPullParserException e) {
+			throw new ContentDecodingException(e.getMessage());
+		} catch (IOException e) {
+			throw new ContentDecodingException(e.getMessage());
+		}
+	}
+	public String peekStartElementAsString() throws ContentDecodingException {
+		int event = readToNextTag(XmlPullParser.START_TAG);
+		if (event != XmlPullParser.START_TAG) {
+			return null;
+		}
+		return _reader.getName();
+	}
+	
+	public Long peekStartElementAsLong() throws ContentDecodingException {
+		String strTag = peekStartElementAsString();
+		if (null == strTag) {
+			return null; // e.g. hit an end tag...
+		}
+		return stringToTag(strTag);
+	}
+	
+	/**
+	 * Helper method to decode text (UTF-8) and binary elements. Consumes the end element,
+	 * behavior which other decoders are forced to match.
+	 * @return the read data, as a String
+	 * @throws ContentDecodingException if there is a problem decoding the data
+	 */
+	public String readUString() throws ContentDecodingException {
+		StringBuffer buf = new StringBuffer();
+		try {
+			int event = _reader.getEventType();;
+			// Handles empty text element.
+			while (event == XmlPullParser.TEXT) {
+				buf.append(_reader.getText());
+				event = _reader.next();
+			}
+			if (event == XmlPullParser.START_TAG) {
+				throw new ContentDecodingException("readElementText expects start element to have been previously consumed, got: " + XmlPullParser.TYPES[event]);
+			} else if (event != XmlPullParser.END_TAG) {
+				throw new ContentDecodingException("Expected end of text element, got: " + XmlPullParser.TYPES[event]);
+			}
+			readEndElement();
+			return buf.toString();
+		} catch (XmlPullParserException e) {
+			throw new ContentDecodingException(e.getMessage(), e);
+		} catch (IOException e) {
+			throw new ContentDecodingException(e.getMessage(), e);
+		}
+	}
+
+	public void readEndElement() throws ContentDecodingException {
+		int event = readToNextTag(XmlPullParser.END_TAG);
+		if (event != XmlPullParser.END_TAG) {
+			throw new ContentDecodingException("Expected end element, got: " + XmlPullParser.TYPES[event]);
+		}
+		try {
+			_reader.next();
+		} catch (XmlPullParserException e) {
+			throw new ContentDecodingException(e.getMessage());
+		} catch (IOException e) {
+			throw new ContentDecodingException(e.getMessage());
+		}
+	}
+
+	/**
+	 * Read a BLOB. Consumes the end element, so force other versions
+	 * to match.
+	 */
+	public byte [] readBlob() throws ContentDecodingException {
+		try {
+			String strElementText = readUString();
+			// readEndElement(); // readElementText consumes end element
+			return TextXMLCodec.decodeBinaryElement(strElementText);
+		} catch (IOException e) {
+			throw new ContentDecodingException(e.getMessage(),e);
+		}
+	}
+	
+	public CCNTime readDateTime(String startTag) throws ContentDecodingException {
+		String strTimestamp = readUTF8Element(startTag);
+		CCNTime timestamp;
+		try {
+			timestamp = TextXMLCodec.parseDateTime(strTimestamp);
+		} catch (ParseException e) {
+			timestamp = null;
+		}
+		if (null == timestamp) {
+			throw new ContentDecodingException("Cannot parse timestamp: " + strTimestamp);
+		}		
+		return timestamp;
+	}
+
+	public CCNTime readDateTime(long startTag) throws ContentDecodingException {
+		String strTimestamp = readUTF8Element(startTag);
+		CCNTime timestamp;
+		try {
+			timestamp = TextXMLCodec.parseDateTime(strTimestamp);
+		} catch (ParseException e) {
+			timestamp = null;
+		}
+		if (null == timestamp) {
+			throw new ContentDecodingException("Cannot parse timestamp: " + strTimestamp);
+		}		
+		return timestamp;
+	}
+
+	private int readToNextTag(int type) throws ContentDecodingException {
+		int event;
+		try {
+			event = _reader.getEventType();
+			if (event == type)
+				return event;
+			if (event == XmlPullParser.TEXT || event == XmlPullParser.COMMENT)
+				event = _reader.next();
+		} catch (IOException e) {
+			throw new ContentDecodingException(e.getMessage(), e);
+		} catch (XmlPullParserException e) {
+			throw new ContentDecodingException(e.getMessage(), e);
+		}
+		return event;
+	}
+};