// BlogBridge -- RSS feed reader, manager, and web based service // Copyright (C) 2002-2006 by R. Pito Salas // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software Foundation; // either version 2 of the License, or (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License along with this program; // if not, write to the Free Software Foundation, Inc., 59 Temple Place, // Suite 330, Boston, MA 02111-1307 USA // // Contact: R. Pito Salas // mailto:pitosalas@users.sourceforge.net // More information: about BlogBridge // http://www.blogbridge.com // http://sourceforge.net/projects/blogbridge // // $Id: XMLFormatDetector.java,v 1.3 2006/11/28 11:05:27 spyromus Exp $ // package com.salas.bb.utils.discovery.detector; import com.salas.bb.utils.net.URLInputStream; import javax.swing.*; import java.awt.*; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * XML Format Detector. */ public class XMLFormatDetector { private static final int STATE_BEGINNING = 0; private static final int STATE_TAG_BEGINNING = 1; private static final int STATE_COMMENT = 2; private static final int STATE_XML_INSTR = 3; private byte[] buf; private int bufPos; /** * Creates detector. */ public XMLFormatDetector() { buf = new byte[4]; } /** * Makes an attempt to read first bytes of the resource to understand its format. * * @param url url. * * @return the format or <code>NULL</code>. * * @throws java.io.IOException in case of I/O error. */ public XMLFormat detect(URL url) throws IOException { return detect(new URLInputStream(url)); } /** * Makes an attempt to read first bytes of the resource to understand its format. * * @param in input stream. * * @return the format or <code>NULL</code>. * * @throws java.io.IOException in case of I/O error. */ public XMLFormat detect(InputStream in) throws IOException { int state = STATE_BEGINNING; bufPos = 0; XMLFormat fmt = null; int b; boolean finished = false; while (!finished && (b = in.read()) != -1) { switch (state) { case STATE_BEGINNING: if (isSpace(b)) continue; else if (b == '<') state = STATE_TAG_BEGINNING; break; case STATE_TAG_BEGINNING: if (b == '?') state = STATE_XML_INSTR; else if (b == '!') { if (in.read() == '-' && in.read() == '-') state = STATE_COMMENT; else state = STATE_XML_INSTR; } else if ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')) append(b); else if (b == ':') bufPos = 0; else { fmt = parseFormat(); finished = true; } break; case STATE_XML_INSTR: if (b == '>') state = STATE_BEGINNING; break; case STATE_COMMENT: if (b == '-' && in.read() == '-' && in.read() == '>') state = STATE_BEGINNING; break; default: break; } } in.close(); return fmt; } /** * Returns <code>TRUE</code> if the character is space. * * @param b character code. * * @return <code>TRUE</code> if the character is space. */ private static boolean isSpace(int b) { return ' ' == b || '\n' == b; } /** * Appends a character and increments the pointer. * * @param b character. */ private void append(int b) { if (bufPos < buf.length) buf[bufPos++] = (byte)b; } /** * Parses the tag name saved in the buffer and returns the format. * * @return format or <code>NULL</code> if unknown. */ private XMLFormat parseFormat() { XMLFormat fmt = null; String str = new String(buf, 0, bufPos).toLowerCase(); if ("rss".equals(str)) fmt = XMLFormat.RSS; else if ("rdf".equals(str)) fmt = XMLFormat.RDF; else if ("feed".equals(str)) fmt = XMLFormat.ATOM; else if ("opml".equals(str)) fmt = XMLFormat.OPML; return fmt; } /** * Makes attempt to detect the format, and asks for clarifications if not able. * * @param url URL to discover. * @param parent parent frame. * * @return the format. */ public static XMLFormat detectOrAskFormat(URL url, Component parent) { XMLFormatDetector detector = new XMLFormatDetector(); XMLFormat fmt; try { fmt = detector.detect(url); } catch (IOException e) { fmt = chooseFormat(parent); } return fmt; } /** * Shows the modal dialog with the format selector. * * @param parent parent dialog. * * @return the format. */ public static XMLFormat chooseFormat(Component parent) { XMLFormat fmt = null; String dataFeed = "Data Feed"; String rl = "Reading List"; Object[] options = { dataFeed, rl }; // TODO: Localize int res = JOptionPane.showOptionDialog(parent, "<html><b>BlogBridge is unable to access the resource.</b>\n\n" + "Please suggest the format:", "BlogBridge", JOptionPane.OK_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, dataFeed); if (res != JOptionPane.CLOSED_OPTION) { fmt = res == 0 ? XMLFormat.ATOM : XMLFormat.OPML; } return fmt; } }