/* * Part of the CCNx Java Library. * * Copyright (C) 2008, 2009, 2011 Palo Alto Research Center, Inc. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. You should have received * a copy of the GNU Lesser General Public License along with this library; * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. */ package org.ccnx.ccn.impl.encoding; import java.io.IOException; import java.text.ParseException; import java.util.TreeMap; import org.ccnx.ccn.io.content.ContentDecodingException; import org.ccnx.ccn.protocol.CCNTime; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; /** * An implementation of XMLDecoder for the Text codec. * * @see TextXMLCodec * @see XMLDecoder */ public class TextXMLDecoder extends GenericXMLDecoder implements XMLDecoder { protected XmlPullParser _reader = null; public TextXMLDecoder() { super(); } public TextXMLDecoder(XMLDictionary dictionary) { super(dictionary); } public void initializeDecoding() throws ContentDecodingException { try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); _reader = factory.newPullParser(); _reader.setInput(_istream, null); } catch (XmlPullParserException e) { throw new ContentDecodingException(e.getMessage(), e); } } public void readStartDocument() throws ContentDecodingException { 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]); } } public void readStartElement(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; } }