Back to project page RssReader.
The source code is released under:
GNU General Public License
If you think the Android project RssReader listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/** * RssReader/* www . ja v a 2 s. c o m*/ * * Copyright (c) 2013-2014 teejoe * * 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 3 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, see <http://www.gnu.org/licenses/>. * * * Some parts of this software are based on "Sparse rss" under the MIT license (see * below). Please refers to the original project to identify which parts are under the * MIT license. * * Copyright (c) 2010-2012 Stefan Handschuh * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.m2x.rssreader.util; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.os.Environment; import android.text.TextUtils; import android.util.Xml; import org.m2x.rssreader.Constants; import org.m2x.rssreader.MainApplication; import org.m2x.rssreader.provider.FeedData.FeedColumns; import org.m2x.rssreader.provider.FeedData.FilterColumns; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class OPML { public static final String BACKUP_OPML = Environment.getExternalStorageDirectory() + "/rssreader_auto_backup.opml"; private static final String[] FEEDS_PROJECTION = new String[]{ FeedColumns._ID, FeedColumns.IS_GROUP, FeedColumns.NAME, FeedColumns.URL, FeedColumns.RETRIEVE_FULLTEXT}; private static final String[] FILTERS_PROJECTION = new String[]{ FilterColumns.FILTER_TEXT, FilterColumns.IS_REGEX, FilterColumns.IS_APPLIED_TO_TITLE}; private static final String START = "<?xml version='1.0' encoding='utf-8'?>\n<opml version='1.1'>\n<head>\n<title>RssReader export</title>\n<dateCreated>"; private static final String AFTER_DATE = "</dateCreated>\n</head>\n<body>\n"; private static final String OUTLINE_TITLE = "\t<outline title='"; private static final String OUTLINE_XMLURL = "' type='rss' xmlUrl='"; private static final String OUTLINE_RETRIEVE_FULLTEXT = "' retrieveFullText='"; private static final String OUTLINE_INLINE_CLOSING = "'/>\n"; private static final String OUTLINE_NORMAL_CLOSING = "'>\n"; private static final String OUTLINE_END = "\t</outline>\n"; private static final String FILTER_TEXT = "\t\t<filter text='"; private static final String FILTER_IS_REGEX = "' isRegex='"; private static final String FILTER_IS_APPLIED_TO_TITLE = "' isAppliedToTitle='"; private static final String FILTER_CLOSING = "'/>\n"; private static final String CLOSING = "</body>\n</opml>\n"; private static final OPMLParser mParser = new OPMLParser(); private static boolean sAutoBackupEnabled = true; public static void importFromFile(String filename) throws IOException, SAXException { if (BACKUP_OPML.equals(filename)) { sAutoBackupEnabled = false; // Do not write the auto backup file while reading it... } try { Xml.parse(new InputStreamReader(new FileInputStream(filename)), mParser); } finally { sAutoBackupEnabled = true; } } public static void importFromFile(InputStream input) throws IOException, SAXException { Xml.parse(new InputStreamReader(input), mParser); } public static void exportToFile(String filename) throws IOException { if (BACKUP_OPML.equals(filename) && !sAutoBackupEnabled) { return; } Cursor cursor = MainApplication.getContext().getContentResolver() .query(FeedColumns.GROUPS_CONTENT_URI, FEEDS_PROJECTION, null, null, null); StringBuilder builder = new StringBuilder(START); builder.append(System.currentTimeMillis()); builder.append(AFTER_DATE); while (cursor.moveToNext()) { builder.append(OUTLINE_TITLE); builder.append(cursor.isNull(2) ? "" : TextUtils.htmlEncode(cursor.getString(2))); if (cursor.getInt(1) == 1) { // If it is a group builder.append(OUTLINE_NORMAL_CLOSING); Cursor cursorChildren = MainApplication.getContext().getContentResolver() .query(FeedColumns.FEEDS_FOR_GROUPS_CONTENT_URI(cursor.getString(0)), FEEDS_PROJECTION, null, null, null); while (cursorChildren.moveToNext()) { builder.append("\t"); builder.append(OUTLINE_TITLE); builder.append(cursorChildren.isNull(2) ? "" : TextUtils.htmlEncode(cursorChildren.getString(2))); builder.append(OUTLINE_XMLURL); builder.append(TextUtils.htmlEncode(cursorChildren.getString(3))); builder.append(OUTLINE_RETRIEVE_FULLTEXT); builder.append(cursorChildren.getInt(4) == 1 ? "true": "false"); Cursor cursorFilters = MainApplication.getContext().getContentResolver().query( FilterColumns.FILTERS_FOR_FEED_CONTENT_URI(cursorChildren.getString(0)), FILTERS_PROJECTION, null, null, null); if (cursorFilters.getCount() != 0) { builder.append(OUTLINE_NORMAL_CLOSING); while (cursorFilters.moveToNext()) { builder.append("\t"); builder.append(FILTER_TEXT); builder.append(TextUtils.htmlEncode(cursorFilters.getString(0))); builder.append(FILTER_IS_REGEX); builder.append(cursorFilters.getInt(1) == 1? "true": "false"); builder.append(FILTER_IS_APPLIED_TO_TITLE); builder.append(cursorFilters.getInt(2) == 1? "true": "false"); builder.append(FILTER_CLOSING); } builder.append("\t"); builder.append(OUTLINE_END); } else { builder.append(OUTLINE_INLINE_CLOSING); } cursorFilters.close(); } cursorChildren.close(); builder.append(OUTLINE_END); } else { builder.append(OUTLINE_XMLURL); builder.append(TextUtils.htmlEncode(cursor.getString(3))); builder.append(OUTLINE_RETRIEVE_FULLTEXT); builder.append(cursor.getInt(4) == 1? "true": "false"); Cursor cursorFilters = MainApplication.getContext().getContentResolver() .query(FilterColumns.FILTERS_FOR_FEED_CONTENT_URI(cursor.getString(0)), FILTERS_PROJECTION, null, null, null); if (cursorFilters.getCount() != 0) { builder.append(OUTLINE_NORMAL_CLOSING); while (cursorFilters.moveToNext()) { builder.append(FILTER_TEXT); builder.append(TextUtils.htmlEncode(cursorFilters.getString(0))); builder.append(FILTER_IS_REGEX); builder.append(cursorFilters.getInt(1) == 1? "true": "false"); builder.append(FILTER_IS_APPLIED_TO_TITLE); builder.append(cursorFilters.getInt(2) == 1? "true": "false"); builder.append(FILTER_CLOSING); } builder.append(OUTLINE_END); } else { builder.append(OUTLINE_INLINE_CLOSING); } cursorFilters.close(); } } builder.append(CLOSING); cursor.close(); BufferedWriter writer = new BufferedWriter(new FileWriter(filename)); writer.write(builder.toString()); writer.close(); } private static class OPMLParser extends DefaultHandler { private static final String TAG_BODY = "body"; private static final String TAG_OUTLINE = "outline"; private static final String ATTRIBUTE_TITLE = "title"; private static final String ATTRIBUTE_XMLURL = "xmlUrl"; private static final String ATTRIBUTE_RETRIEVE_FULLTEXT = "retrieveFullText"; private static final String TAG_FILTER = "filter"; private static final String ATTRIBUTE_TEXT = "text"; private static final String ATTRIBUTE_IS_REGEX = "isRegex"; private static final String ATTRIBUTE_IS_APPLIED_TO_TITLE = "isAppliedToTitle"; private boolean bodyTagEntered = false; private boolean feedEntered = false; private boolean probablyValidElement = false; private String groupId = null; private String feedId = null; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (!bodyTagEntered) { if (TAG_BODY.equals(localName)) { bodyTagEntered = true; probablyValidElement = true; } } else if (TAG_OUTLINE.equals(localName)) { String url = attributes.getValue("", ATTRIBUTE_XMLURL); String title = attributes.getValue("", ATTRIBUTE_TITLE); ContentResolver cr = MainApplication.getContext().getContentResolver(); if (url == null) { // No url => this is a group if (title != null) { ContentValues values = new ContentValues(); values.put(FeedColumns.IS_GROUP, true); values.put(FeedColumns.NAME, title); Cursor cursor = cr.query(FeedColumns.GROUPS_CONTENT_URI, null, FeedColumns.NAME + Constants.DB_ARG, new String[]{title}, null); if (!cursor.moveToFirst()) { groupId = cr.insert(FeedColumns.GROUPS_CONTENT_URI, values) .getLastPathSegment(); } cursor.close(); } } else { // Url => this is a feed feedEntered = true; ContentValues values = new ContentValues(); values.put(FeedColumns.URL, url); values.put(FeedColumns.NAME, title != null && title.length() > 0 ? title : null); if (groupId != null) { values.put(FeedColumns.GROUP_ID, groupId); } values.put(FeedColumns.RETRIEVE_FULLTEXT, "true".equals( attributes.getValue("", ATTRIBUTE_RETRIEVE_FULLTEXT))); Cursor cursor = cr.query(FeedColumns.CONTENT_URI, null, FeedColumns.URL + Constants.DB_ARG, new String[]{url}, null); feedId = null; if (!cursor.moveToFirst()) { feedId = cr.insert(FeedColumns.CONTENT_URI, values).getLastPathSegment(); } cursor.close(); } } else if (TAG_FILTER.equals(localName)) { if (feedEntered && feedId != null) { ContentValues values = new ContentValues(); values.put(FilterColumns.FILTER_TEXT, attributes.getValue("", ATTRIBUTE_TEXT)); values.put(FilterColumns.IS_REGEX, "true".equals( attributes.getValue("", ATTRIBUTE_IS_REGEX))); values.put(FilterColumns.IS_APPLIED_TO_TITLE, "true".equals( attributes.getValue("", ATTRIBUTE_IS_APPLIED_TO_TITLE))); ContentResolver cr = MainApplication.getContext().getContentResolver(); cr.insert(FilterColumns.FILTERS_FOR_FEED_CONTENT_URI(feedId), values); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (bodyTagEntered && TAG_BODY.equals(localName)) { bodyTagEntered = false; } else if (TAG_OUTLINE.equals(localName)) { if (feedEntered) { feedEntered = false; } else { groupId = null; } } } @Override public void warning(SAXParseException e) throws SAXException { // ignore warnings } @Override public void error(SAXParseException e) throws SAXException { // ignore small errors } @Override public void endDocument() throws SAXException { if (!probablyValidElement) { throw new SAXException(); } else { super.endDocument(); } } } }