package com.vaguehope.onosendai.util; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.net.URLConnection; import org.ccil.cowan.tagsoup.jaxp.SAXParserImpl; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import android.text.Html; import android.text.Spanned; import com.vaguehope.onosendai.util.HttpHelper.HttpStreamHandler; public enum HtmlTitleParser implements HttpStreamHandler<Spanned> { INSTANCE; private static final String CHARSET = "charset="; private static final int MAX_SEARCH_LENGTH = 10 * 1024; // If the </title> is more than this into the page then... well dam. @Override public void onError (final Exception e) {/* Unused. */} @Override public Spanned handleStream (final URLConnection connection, final InputStream is, final int contentLength) throws IOException { final String charset = parseCharset(connection.getHeaderField("Content-Type")); try { final HtmlTitleHandler h = new HtmlTitleHandler(); SAXParserImpl.newInstance(null).parse(new InputSource(new StringReader(IoHelper.toString(is, MAX_SEARCH_LENGTH, charset))), h); final String title = h.getTitle(); if (StringHelper.isEmpty(title)) return null; return Html.fromHtml(title); } catch (final SAXException e) { throw new IOException(e.toString(), e); } } // e.g. Content-Type: text/html; charset=ISO-8859-1 private static String parseCharset (final String contentType) { if (contentType == null) return null; for (String part : contentType.split(";")) { if (part != null) { part = part.trim(); if (part.startsWith(CHARSET)) { return part.substring(CHARSET.length()).trim(); } } } return null; } private static class HtmlTitleHandler extends DefaultHandler { private final StringBuilder currentText = new StringBuilder(); private boolean keepChar = false; private String title; public HtmlTitleHandler () {} public String getTitle () { return this.title; } @Override public void startElement (final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { final String elementName = !localName.isEmpty() ? localName : qName; if (this.title == null && "title".equalsIgnoreCase(elementName)) { this.keepChar = true; this.currentText.setLength(0); } } @Override public void endElement (final String uri, final String localName, final String qName) throws SAXException { final String elementName = !localName.isEmpty() ? localName : qName; if (this.title == null && "title".equalsIgnoreCase(elementName)) { this.title = this.currentText.toString().trim(); this.keepChar = false; } } @Override public void characters (final char[] ch, final int start, final int length) throws SAXException { if (this.keepChar) this.currentText.append(ch, start, length); } } }