/********************************************************************************** * nWordPress is an automated migration of WordPress 2.5.1 performed by Numiton. * * copyright : (C) 2008 Numiton - www.numiton.com * email : numiton@users.sourceforge.net * * $Id: MagpieRSS.java,v 1.4 2008/10/14 13:15:48 numiton Exp $ * **********************************************************************************/ /********************************************************************************** * * 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 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. * ***************************************************************************/ package org.numiton.nwp.wp_includes; import static com.numiton.PhpCommonConstants.BOOLEAN_FALSE; import static com.numiton.VarHandling.*; import java.io.Serializable; import org.apache.log4j.Logger; import org.numiton.nwp.GlobalConsts; import org.numiton.nwp.GlobalVars; import com.numiton.array.Array; import com.numiton.array.ArrayEntry; import com.numiton.error.ErrorHandling; import com.numiton.generic.*; import com.numiton.ntile.til.libraries.php.quercus.QRegExPosix; import com.numiton.string.Strings; import com.numiton.xml.XMLParser; public class MagpieRSS implements ContextCarrierInterface, Serializable, Cloneable { private static final long serialVersionUID = 3145198352238593998L; protected static final Logger LOG = Logger.getLogger(MagpieRSS.class.getName()); public transient GlobalConsts gConsts; public transient GlobalVars gVars; public int parser; public Array<Object> current_item = new Array<Object>(); // item currently being parsed public Array<Object> items = new Array<Object>(); // collection of parsed items public Array<Object> channel = new Array<Object>(); // hash of channel fields public Array<Object> textinput = new Array<Object>(); public Array<Object> image = new Array<Object>(); public Object feed_type; public String feed_version; // parser variables public Array<String> stack = new Array<String>(); // parser stack public boolean inchannel = false; public boolean initem = false; public String incontent; // if in Atom <content mode="xml"> field public boolean intextinput = false; public boolean inimage = false; public String current_field = ""; public String current_namespace = ""; //var $ERROR = ""; public Array<Object> _CONTENT_CONSTRUCTS = new Array<Object>(new ArrayEntry<Object>("content"), new ArrayEntry<Object>("summary"), new ArrayEntry<Object>("info"), new ArrayEntry<Object>("title"), new ArrayEntry<Object>("tagline"), new ArrayEntry<Object>("copyright")); /** * Generated in place of local variable 'el' from method * 'feed_start_element' because it is used inside an inner class. */ String feed_start_element_el = null; /** * Generated in place of local variable 'ns' from method * 'feed_start_element' because it is used inside an inner class. */ String feed_start_element_ns = null; public int from_cache; public String etag; public String last_modified; public Object ERROR; public MagpieRSS(GlobalVars javaGlobalVariables, GlobalConsts javaGlobalConstants, String source) { setContext(javaGlobalVariables, javaGlobalConstants); int parser = 0; int status = 0; int errorcode = 0; String xml_error = null; int error_line = 0; int error_col = 0; String errormsg = null; // if PHP xml isn't compiled in, die // if (!true)/*Modified by Numiton*/ { ErrorHandling.trigger_error(gVars.webEnv, "Failed to load PHP\'s XML Extension. http://www.php.net/manual/en/ref.xml.php"); } parser = XMLParser.xml_parser_create(gVars.webEnv); if (!is_resource(parser)) { ErrorHandling.trigger_error(gVars.webEnv, "Failed to create an instance of PHP\'s XML parser. http://www.php.net/manual/en/ref.xml.php"); } this.parser = parser; // pass in parser, and a reference to this object // setup handlers // XMLParser.xml_set_object(gVars.webEnv, this.parser, this); XMLParser.xml_set_element_handler(gVars.webEnv, this.parser, new Callback("feed_start_element", this), new Callback("feed_end_element", this)); XMLParser.xml_set_character_data_handler(gVars.webEnv, this.parser, new Callback("feed_cdata", this)); status = XMLParser.xml_parse(gVars.webEnv, this.parser, source); if (!booleanval(status)) { errorcode = XMLParser.xml_get_error_code(gVars.webEnv, this.parser); if (!equal(errorcode, XMLParser.XML_ERROR_NONE)) { xml_error = XMLParser.xml_error_string(errorcode); error_line = XMLParser.xml_get_current_line_number(gVars.webEnv, this.parser); error_col = XMLParser.xml_get_current_column_number(gVars.webEnv, this.parser); errormsg = xml_error + " at line " + strval(error_line) + ", column " + strval(error_col); this.error(errormsg); } } XMLParser.xml_parser_free(gVars.webEnv, this.parser); this.normalize(); } public void feed_start_element(int p, String element, Array<Object> attrs) { String attrs_str = null; String link_el = null; feed_start_element_el = element = Strings.strtolower(element); attrs = Array.array_change_key_case(attrs, Array.CASE_LOWER); // check for a namespace, and split if found feed_start_element_ns = ""; if (BOOLEAN_FALSE != Strings.strpos(element, ":")) { new ListAssigner<String>() { public Array<String> doAssign(Array<String> srcArray) { if (strictEqual(srcArray, null)) { return null; } feed_start_element_ns = srcArray.getValue(0); feed_start_element_el = srcArray.getValue(1); return srcArray; } }.doAssign(QRegExPosix.split(":", element, 2)); } if (booleanval(feed_start_element_ns) && !equal(feed_start_element_ns, "rdf")) { this.current_namespace = feed_start_element_ns; } // if feed type isn't set, then this is first element of feed // identify feed from root element // if (!isset(this.feed_type)) { if (equal(feed_start_element_el, "rdf")) { this.feed_type = gConsts.getRSS(); this.feed_version = "1.0"; } else if (equal(feed_start_element_el, "rss")) { this.feed_type = gConsts.getRSS(); this.feed_version = strval(attrs.getValue("version")); } else if (equal(feed_start_element_el, "feed")) { this.feed_type = gConsts.getATOM(); this.feed_version = strval(attrs.getValue("version")); this.inchannel = true; } return; } if (equal(feed_start_element_el, "channel")) { this.inchannel = true; } else if (equal(feed_start_element_el, "item") || equal(feed_start_element_el, "entry")) { this.initem = true; if (isset(attrs.getValue("rdf:about"))) { this.current_item.putValue("about", attrs.getValue("rdf:about")); } } // if we're in the default namespace of an RSS feed, // record textinput or image fields else if (equal(this.feed_type, gConsts.getRSS()) && equal(this.current_namespace, "") && equal(feed_start_element_el, "textinput")) { this.intextinput = true; } else if (equal(this.feed_type, gConsts.getRSS()) && equal(this.current_namespace, "") && equal(feed_start_element_el, "image")) { this.inimage = true; } // handle atom content constructs else if (equal(this.feed_type, gConsts.getATOM()) && Array.in_array(feed_start_element_el, this._CONTENT_CONSTRUCTS)) { // avoid clashing w/ RSS mod_content if (equal(feed_start_element_el, "content")) { feed_start_element_el = "atom_content"; } this.incontent = feed_start_element_el; } // if inside an Atom content construct (e.g. content or summary) field treat tags as text else if (equal(this.feed_type, gConsts.getATOM()) && booleanval(this.incontent)) { // if tags are inlined, then flatten attrs_str = Strings.join(" ", Array.array_map(new Callback("map_attrs", this), Array.array_keys(attrs), Array.array_values(attrs))); this.append_content("<" + element + " " + attrs_str + ">"); Array.array_unshift(this.stack, feed_start_element_el); } // Atom support many links per containging element. // Magpie treats link elements of type rel='alternate' // as being equivalent to RSS's simple link element. // else if (equal(this.feed_type, gConsts.getATOM()) && equal(feed_start_element_el, "link")) { if (isset(attrs.getValue("rel")) && equal(attrs.getValue("rel"), "alternate")) { link_el = "link"; } else { link_el = "link_" + strval(attrs.getValue("rel")); } this.append(link_el, strval(attrs.getValue("href"))); } // set stack[0] to current element else { Array.array_unshift(this.stack, feed_start_element_el); } } public void feed_cdata(int p, String text) { String current_el = null; if (equal(this.feed_type, gConsts.getATOM()) && booleanval(this.incontent)) { this.append_content(strval(text)); } else { current_el = Strings.join("_", Array.array_reverse(this.stack)); this.append(current_el, strval(text)); } } public void feed_end_element(int p, String el) { el = Strings.strtolower(el); if (equal(el, "item") || equal(el, "entry")) { this.items.putValue(this.current_item); this.current_item = new Array<Object>(); this.initem = false; } else if (equal(this.feed_type, gConsts.getRSS()) && equal(this.current_namespace, "") && equal(el, "textinput")) { this.intextinput = false; } else if (equal(this.feed_type, gConsts.getRSS()) && equal(this.current_namespace, "") && equal(el, "image")) { this.inimage = false; } else if (equal(this.feed_type, gConsts.getATOM()) && Array.in_array(el, this._CONTENT_CONSTRUCTS)) { this.incontent = strval(false); } else if (equal(el, "channel") || equal(el, "feed")) { this.inchannel = false; } else if (equal(this.feed_type, gConsts.getATOM()) && booleanval(this.incontent)) { // balance tags properly // note: i don't think this is actually neccessary if (equal(this.stack.getValue(0), el)) { this.append_content("</" + el + ">"); } else { this.append_content("<" + el + " />"); } Array.array_shift(this.stack); } else { Array.array_shift(this.stack); } this.current_namespace = ""; } public void concat(Ref str1, String str2) { if (!isset(str1.value)) { str1.value = ""; } str1.value = strval(str1.value) + str2; } public void append_content(String text) { if (this.initem) { this.concat(this.current_item.getRef(this.incontent), text); } else if (this.inchannel) { this.concat(this.channel.getRef(this.incontent), text); } } // smart append - field and namespace aware public void append(String el, String text) { if (!booleanval(el)) { return; } if (booleanval(this.current_namespace)) { if (this.initem) { this.concat(this.current_item.getArrayValue(this.current_namespace).getRef(el), text); } else if (this.inchannel) { this.concat(this.channel.getArrayValue(this.current_namespace).getRef(el), text); } else if (this.intextinput) { this.concat(this.textinput.getArrayValue(this.current_namespace).getRef(el), text); } else if (this.inimage) { this.concat(this.image.getArrayValue(this.current_namespace).getRef(el), text); } } else { if (this.initem) { this.concat(this.current_item.getRef(el), text); } else if (this.intextinput) { this.concat(this.textinput.getRef(el), text); } else if (this.inimage) { this.concat(this.image.getRef(el), text); } else if (this.inchannel) { this.concat(this.channel.getRef(el), text); } } } public void normalize() { Array<Object> item = new Array<Object>(); int i = 0; // if atom populate rss fields if (booleanval(this.is_atom())) { this.channel.putValue("descripton", this.channel.getValue("tagline")); for (i = 0; i < Array.count(this.items); i++) { item = this.items.getArrayValue(i); if (isset(item.getValue("summary"))) { item.putValue("description", item.getValue("summary")); } if (isset(item.getValue("atom_content"))) { item.getArrayValue("content").putValue("encoded", item.getValue("atom_content")); } this.items.putValue(i, item); } } else if (booleanval(this.is_rss())) { this.channel.putValue("tagline", this.channel.getValue("description")); for (i = 0; i < Array.count(this.items); i++) { item = this.items.getArrayValue(i); if (isset(item.getValue("description"))) { item.putValue("summary", item.getValue("description")); } if (isset(item.getArrayValue("content").getValue("encoded"))) { item.putValue("atom_content", item.getArrayValue("content").getValue("encoded")); } this.items.putValue(i, item); } } } public String is_rss() { if (equal(this.feed_type, gConsts.getRSS())) { return this.feed_version; } else { return strval(false); } } public String is_atom() { if (equal(this.feed_type, gConsts.getATOM())) { return this.feed_version; } else { return strval(false); } } public String map_attrs(Object k, Object v) { return strval(k) + "=\"" + strval(v) + "\""; } public void error(String errormsg) { error(errormsg, ErrorHandling.E_USER_WARNING); } public void error(String errormsg, int lvl) { // append PHP's error message if track_errors enabled if (isset(ErrorHandling.getLastErrorMessage(gVars.webEnv))) { errormsg = errormsg + " (" + ErrorHandling.getLastErrorMessage(gVars.webEnv) + ")"; } if (booleanval(gConsts.getMAGPIE_DEBUG())) { ErrorHandling.trigger_error(gVars.webEnv, errormsg, lvl); } else { ErrorHandling.error_log(gVars.webEnv, errormsg, 0); } } public void setContext(GlobalVariablesContainer javaGlobalVariables, GlobalConstantsInterface javaGlobalConstants) { gConsts = (GlobalConsts) javaGlobalConstants; gVars = (GlobalVars) javaGlobalVariables; gVars.gConsts = gConsts; } public Object clone() throws CloneNotSupportedException { return super.clone(); } public GlobalVariablesContainer getGlobalVars() { return gVars; } }