Convert feed processor data away from XPCOM

This changes the feed processor XPCOM array and property bags to native arrays
and objects.
This commit is contained in:
J. Ryan Stinnett 2021-05-09 00:20:07 +01:00
parent 75eb8c51d4
commit be80598c6b
2 changed files with 110 additions and 190 deletions

View file

@ -108,7 +108,7 @@ Zotero.FeedReader = function (url) {
let items = this._feed.items; let items = this._feed.items;
if (items && items.length) { if (items && items.length) {
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
let item = items.queryElementAt(i, Components.interfaces.nsIFeedEntry); let item = items[i];
if (!item) continue; if (!item) continue;
let feedItem = Zotero.FeedReader._getFeedItem(item, this._feedProperties); let feedItem = Zotero.FeedReader._getFeedItem(item, this._feedProperties);
@ -295,7 +295,7 @@ Zotero.FeedReader._processCreators = function (feedEntry, field, role) {
try { try {
let personArr = feedEntry[field]; // Seems like this part can throw if there is no author data in the feed let personArr = feedEntry[field]; // Seems like this part can throw if there is no author data in the feed
for (let i = 0; i < personArr.length; i++) { for (let i = 0; i < personArr.length; i++) {
let person = personArr.queryElementAt(i, Components.interfaces.nsIFeedPerson); let person = personArr[i];
if (!person || !person.name) continue; if (!person || !person.name) continue;
let name = Zotero.Utilities.cleanTags(Zotero.Utilities.trimInternal(person.name)); let name = Zotero.Utilities.cleanTags(Zotero.Utilities.trimInternal(person.name));
@ -321,8 +321,6 @@ Zotero.FeedReader._processCreators = function (feedEntry, field, role) {
} }
} }
catch (e) { catch (e) {
if (e.result != Components.results.NS_ERROR_FAILURE) throw e;
if (field != 'authors') return []; if (field != 'authors') return [];
// ieeexplore places these in "authors"... sigh // ieeexplore places these in "authors"... sigh
@ -502,18 +500,16 @@ let ns = {
}; };
Zotero.FeedReader._getFeedField = function (feedEntry, field, namespace) { Zotero.FeedReader._getFeedField = function (feedEntry, field, namespace) {
let prefix = namespace ? ns[namespace] || 'null' : ''; let prefix = namespace ? ns[namespace] || 'null' : '';
try { if (feedEntry.fields[prefix + field]) {
return feedEntry.fields.getPropertyAsAUTF8String(prefix + field); return feedEntry.fields[prefix + field];
} }
catch (e) {}
try { if (namespace && !ns[namespace]) {
if (namespace && !ns[namespace]) { prefix = namespace + ':';
prefix = namespace + ':'; if (feedEntry.fields[prefix + field]) {
return feedEntry.fields.getPropertyAsAUTF8String(prefix + field); return feedEntry.fields[prefix + field];
} }
} }
catch (e) { }
return null; return null;
}; };
@ -523,9 +519,9 @@ Zotero.FeedReader._getEnclosedItems = function (feedEntry) {
if (feedEntry.enclosures) { if (feedEntry.enclosures) {
for (let i = 0; i < feedEntry.enclosures.length; i++) { for (let i = 0; i < feedEntry.enclosures.length; i++) {
let elem = feedEntry.enclosures.queryElementAt(0, Components.interfaces.nsIPropertyBag2); let elem = feedEntry.enclosures[0];
if (elem.get('url')) { if (elem.url) {
let enclosedItem = { url: elem.get('url'), contentType: elem.get('type') || '' }; let enclosedItem = { url: elem.url, contentType: elem.type || '' };
enclosedItems.push(enclosedItem); enclosedItems.push(enclosedItem);
} }
} }

View file

@ -10,8 +10,6 @@ function LOG(str) {
Zotero.debug("Feed Processor: " + str); Zotero.debug("Feed Processor: " + str);
} }
const BAG_CONTRACTID = "@mozilla.org/hash-property-bag;1";
const ARRAY_CONTRACTID = "@mozilla.org/array;1";
const SAX_CONTRACTID = "@mozilla.org/saxparser/xmlreader;1"; const SAX_CONTRACTID = "@mozilla.org/saxparser/xmlreader;1";
const PARSERUTILS_CONTRACTID = "@mozilla.org/parserutils;1"; const PARSERUTILS_CONTRACTID = "@mozilla.org/parserutils;1";
@ -74,12 +72,12 @@ const IANA_URI = "http://www.iana.org/assignments/relation/";
function findAtomLinks(rel, links) { function findAtomLinks(rel, links) {
var rvLinks = []; var rvLinks = [];
for (var i = 0; i < links.length; ++i) { for (var i = 0; i < links.length; ++i) {
var linkElement = links.queryElementAt(i, Ci.nsIPropertyBag2); var linkElement = links[i];
// atom:link MUST have @href // atom:link MUST have @href
if (bagHasKey(linkElement, "href")) { if (linkElement.href) {
var relAttribute = null; var relAttribute = null;
if (bagHasKey(linkElement, "rel")) { if (linkElement.rel) {
relAttribute = linkElement.getPropertyAsAString("rel"); relAttribute = linkElement.rel;
} }
if ((!relAttribute && rel == "alternate") || relAttribute == rel) { if ((!relAttribute && rel == "alternate") || relAttribute == rel) {
rvLinks.push(linkElement); rvLinks.push(linkElement);
@ -103,34 +101,9 @@ function xmlEscape(s) {
return s; return s;
} }
function arrayContains(array, element) {
for (var i = 0; i < array.length; ++i) {
if (array[i] == element) {
return true;
}
}
return false;
}
// XXX add hasKey to nsIPropertyBag
function bagHasKey(bag, key) {
try {
bag.getProperty(key);
return true;
}
catch (e) {
return false;
}
}
function makePropGetter(key) { function makePropGetter(key) {
return function (bag) { return function(bag) {
try { return bag[key];
return bag.getProperty(key);
}
catch (e) {
}
return null;
}; };
} }
@ -179,12 +152,12 @@ FeedResult.prototype = {
function Feed() { function Feed() {
this.subtitle = null; this.subtitle = null;
this.title = null; this.title = null;
this.items = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray); this.items = [];
this.link = null; this.link = null;
this.id = null; this.id = null;
this.generator = null; this.generator = null;
this.authors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray); this.authors = [];
this.contributors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray); this.contributors = [];
this.baseURI = null; this.baseURI = null;
this.enclosureCount = 0; this.enclosureCount = 0;
this.type = Ci.nsIFeed.TYPE_FEED; this.type = Ci.nsIFeed.TYPE_FEED;
@ -226,10 +199,10 @@ Feed.prototype = {
normalize: function () { normalize: function () {
fieldsToObj(this, this.searchLists); fieldsToObj(this, this.searchLists);
if (this.skipDays) { if (this.skipDays) {
this.skipDays = this.skipDays.getProperty("days"); this.skipDays = this.skipDays.days;
} }
if (this.skipHours) { if (this.skipHours) {
this.skipHours = this.skipHours.getProperty("hours"); this.skipHours = this.skipHours.hours;
} }
if (this.updated) { if (this.updated) {
@ -237,14 +210,14 @@ Feed.prototype = {
} }
// Assign Atom link if needed // Assign Atom link if needed
if (bagHasKey(this.fields, "links")) { if (this.fields.links) {
this._atomLinksToURI(); this._atomLinksToURI();
} }
this._calcEnclosureCountAndFeedType(); this._calcEnclosureCountAndFeedType();
// Resolve relative image links // Resolve relative image links
if (this.image && bagHasKey(this.image, "url")) { if (this.image && this.image.url) {
this._resolveImageLink(); this._resolveImageLink();
} }
@ -259,16 +232,15 @@ Feed.prototype = {
var otherCount = 0; var otherCount = 0;
for (var i = 0; i < this.items.length; ++i) { for (var i = 0; i < this.items.length; ++i) {
var entry = this.items.queryElementAt(i, Ci.nsIFeedEntry); var entry = this.items[i];
entry.QueryInterface(Ci.nsIFeedContainer);
if (entry.enclosures && entry.enclosures.length > 0) { if (entry.enclosures && entry.enclosures.length > 0) {
++entriesWithEnclosures; ++entriesWithEnclosures;
for (var e = 0; e < entry.enclosures.length; ++e) { for (var e = 0; e < entry.enclosures.length; ++e) {
var enc = entry.enclosures.queryElementAt(e, Ci.nsIWritablePropertyBag2); var enc = entry.enclosures[e];
if (enc.hasKey("type")) { if (enc.type) {
var enctype = enc.get("type"); var enctype = enc.type;
if (/^audio/.test(enctype)) { if (/^audio/.test(enctype)) {
++audioCount; ++audioCount;
@ -317,13 +289,13 @@ Feed.prototype = {
}, },
_atomLinksToURI: function () { _atomLinksToURI: function () {
var links = this.fields.getPropertyAsInterface("links", Ci.nsIArray); var links = this.fields.links;
var alternates = findAtomLinks("alternate", links); var alternates = findAtomLinks("alternate", links);
if (alternates.length > 0) { if (alternates.length > 0) {
var href = alternates[0].getPropertyAsAString("href"); var href = alternates[0].href;
var base; var base;
if (bagHasKey(alternates[0], "xml:base")) { if (alternates[0]["xml:base"]) {
base = alternates[0].getPropertyAsAString("xml:base"); base = alternates[0]["xml:base"];
} }
this.link = this._resolveURI(href, base); this.link = this._resolveURI(href, base);
} }
@ -331,12 +303,12 @@ Feed.prototype = {
_resolveImageLink: function () { _resolveImageLink: function () {
var base; var base;
if (bagHasKey(this.image, "xml:base")) { if (this.image["xml:base"]) {
base = this.image.getPropertyAsAString("xml:base"); base = this.image["xml:base"];
} }
var url = this._resolveURI(this.image.getPropertyAsAString("url"), base); var url = this._resolveURI(this.image.url, base);
if (url) { if (url) {
this.image.setPropertyAsAString("url", url.spec); this.image.url = url.spec;
} }
}, },
@ -357,9 +329,9 @@ Feed.prototype = {
_resetBagMembersToRawText: function (fieldLists) { _resetBagMembersToRawText: function (fieldLists) {
for (var i = 0; i < fieldLists.length; i++) { for (var i = 0; i < fieldLists.length; i++) {
for (var j = 0; j < fieldLists[i].length; j++) { for (var j = 0; j < fieldLists[i].length; j++) {
if (bagHasKey(this.fields, fieldLists[i][j])) { if (this.fields[fieldLists[i][j]]) {
var textConstruct = this.fields.getProperty(fieldLists[i][j]); var textConstruct = this.fields[fieldLists[i][j]];
this.fields.setPropertyAsAString(fieldLists[i][j], textConstruct.text); this.fields[fieldLists[i][j]] = textConstruct.text;
} }
} }
} }
@ -371,14 +343,14 @@ function Entry() {
this.summary = null; this.summary = null;
this.content = null; this.content = null;
this.title = null; this.title = null;
this.fields = Cc["@mozilla.org/hash-property-bag;1"].createInstance(Ci.nsIWritablePropertyBag2); this.fields = {};
this.link = null; this.link = null;
this.id = null; this.id = null;
this.baseURI = null; this.baseURI = null;
this.updated = null; this.updated = null;
this.published = null; this.published = null;
this.authors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray); this.authors = [];
this.contributors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray); this.contributors = [];
} }
Entry.prototype = { Entry.prototype = {
@ -420,7 +392,7 @@ Entry.prototype = {
fieldsToObj(this, this.searchLists); fieldsToObj(this, this.searchLists);
// Assign Atom link if needed // Assign Atom link if needed
if (bagHasKey(this.fields, "links")) { if (this.fields.links) {
this._atomLinksToURI(); this._atomLinksToURI();
} }
@ -428,16 +400,16 @@ Entry.prototype = {
this._populateEnclosures(); this._populateEnclosures();
// The link might be a guid w/ permalink=true // The link might be a guid w/ permalink=true
if (!this.link && bagHasKey(this.fields, "guid")) { if (!this.link && this.fields.guid) {
var guid = this.fields.getProperty("guid"); var guid = this.fields.guid;
var isPermaLink = true; var isPermaLink = true;
if (bagHasKey(guid, "isPermaLink")) { if (guid.isPermaLink) {
isPermaLink = guid.getProperty("isPermaLink").toLowerCase() != "false"; isPermaLink = guid.isPermaLink.toLowerCase() != "false";
} }
if (guid && isPermaLink) { if (guid && isPermaLink) {
this.link = strToURI(guid.getProperty("guid")); this.link = strToURI(guid.guid);
} }
} }
@ -456,27 +428,27 @@ Entry.prototype = {
}, },
_populateEnclosures: function () { _populateEnclosures: function () {
if (bagHasKey(this.fields, "links")) { if (this.fields.links) {
this._atomLinksToEnclosures(); this._atomLinksToEnclosures();
} }
// Add RSS2 enclosure to enclosures // Add RSS2 enclosure to enclosures
if (bagHasKey(this.fields, "enclosure")) { if (this.fields.enclosure) {
this._enclosureToEnclosures(); this._enclosureToEnclosures();
} }
// Add media:content to enclosures // Add media:content to enclosures
if (bagHasKey(this.fields, "mediacontent")) { if (this.fields.mediacontent) {
this._mediaToEnclosures("mediacontent"); this._mediaToEnclosures("mediacontent");
} }
// Add media:thumbnail to enclosures // Add media:thumbnail to enclosures
if (bagHasKey(this.fields, "mediathumbnail")) { if (this.fields.mediathumbnail) {
this._mediaToEnclosures("mediathumbnail"); this._mediaToEnclosures("mediathumbnail");
} }
// Add media:content in media:group to enclosures // Add media:content in media:group to enclosures
if (bagHasKey(this.fields, "mediagroup")) { if (this.fields.mediagroup) {
this._mediaToEnclosures("mediagroup", "mediacontent"); this._mediaToEnclosures("mediagroup", "mediacontent");
} }
}, },
@ -486,7 +458,7 @@ Entry.prototype = {
_addToEnclosures: function (newEnc) { _addToEnclosures: function (newEnc) {
// items we add to the enclosures array get displayed in the FeedWriter and // items we add to the enclosures array get displayed in the FeedWriter and
// they must have non-empty urls. // they must have non-empty urls.
if (!bagHasKey(newEnc, "url") || newEnc.getPropertyAsAString("url") == "") { if (!newEnc.url || newEnc.url == "") {
return; return;
} }
@ -494,40 +466,37 @@ Entry.prototype = {
this.__enclosureMap = {}; this.__enclosureMap = {};
} }
var previousEnc = this.__enclosureMap[newEnc.getPropertyAsAString("url")]; var previousEnc = this.__enclosureMap[newEnc.url];
if (previousEnc != undefined) { if (previousEnc != undefined) {
previousEnc.QueryInterface(Ci.nsIWritablePropertyBag2); if (!previousEnc.type && newEnc.type) {
previousEnc.type = newEnc.type;
if (!bagHasKey(previousEnc, "type") && bagHasKey(newEnc, "type")) {
previousEnc.setPropertyAsAString("type", newEnc.getPropertyAsAString("type"));
try { try {
let handlerInfoWrapper = gMimeService.getFromTypeAndExtension(newEnc.getPropertyAsAString("type"), null); let handlerInfoWrapper = gMimeService.getFromTypeAndExtension(newEnc.type, null);
if (handlerInfoWrapper && handlerInfoWrapper.description) { if (handlerInfoWrapper && handlerInfoWrapper.description) {
previousEnc.setPropertyAsAString("typeDesc", handlerInfoWrapper.description); previousEnc.typeDesc = handlerInfoWrapper.description;
} }
} }
catch (ext) {} catch (ext) {}
} }
if (!bagHasKey(previousEnc, "length") && bagHasKey(newEnc, "length")) { if (!previousEnc.length && newEnc.length) {
previousEnc.setPropertyAsAString("length", newEnc.getPropertyAsAString("length")); previousEnc.length = newEnc.length;
} }
return; return;
} }
if (this.enclosures === null) { if (this.enclosures === null) {
this.enclosures = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray); this.enclosures = [];
this.enclosures.QueryInterface(Ci.nsIMutableArray);
} }
this.enclosures.appendElement(newEnc); this.enclosures.push(newEnc);
this.__enclosureMap[newEnc.getPropertyAsAString("url")] = newEnc; this.__enclosureMap[newEnc.url] = newEnc;
}, },
_atomLinksToEnclosures: function () { _atomLinksToEnclosures: function () {
var links = this.fields.getPropertyAsInterface("links", Ci.nsIArray); var links = this.fields.links;
var encLinks = findAtomLinks("enclosure", links); var encLinks = findAtomLinks("enclosure", links);
if (encLinks.length == 0) { if (encLinks.length == 0) {
return; return;
@ -537,19 +506,19 @@ Entry.prototype = {
var link = encLinks[i]; var link = encLinks[i];
// an enclosure must have an href // an enclosure must have an href
if (!(link.getProperty("href"))) { if (!link.href) {
return; return;
} }
var enc = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2); var enc = {};
// copy Atom bits over to equivalent enclosure bits // copy Atom bits over to equivalent enclosure bits
enc.setPropertyAsAString("url", link.getPropertyAsAString("href")); enc.url = link.href;
if (bagHasKey(link, "type")) { if (link.type) {
enc.setPropertyAsAString("type", link.getPropertyAsAString("type")); enc.type = link.type;
} }
if (bagHasKey(link, "length")) { if (link.length) {
enc.setPropertyAsAString("length", link.getPropertyAsAString("length")); enc.length = link.length;
} }
this._addToEnclosures(enc); this._addToEnclosures(enc);
@ -557,9 +526,9 @@ Entry.prototype = {
}, },
_enclosureToEnclosures: function () { _enclosureToEnclosures: function () {
var enc = this.fields.getPropertyAsInterface("enclosure", Ci.nsIPropertyBag2); var enc = this.fields.enclosure;
if (!(enc.getProperty("url"))) { if (!enc.url) {
return; return;
} }
@ -572,37 +541,37 @@ Entry.prototype = {
// If a contentType is specified, the mediaType is a simple propertybag, // If a contentType is specified, the mediaType is a simple propertybag,
// and the contentType is an array inside it. // and the contentType is an array inside it.
if (contentType) { if (contentType) {
var group = this.fields.getPropertyAsInterface(mediaType, Ci.nsIPropertyBag2); var group = this.fields[mediaType];
content = group.getPropertyAsInterface(contentType, Ci.nsIArray); content = group[contentType];
} }
else { else {
content = this.fields.getPropertyAsInterface(mediaType, Ci.nsIArray); content = this.fields[mediaType];
} }
for (var i = 0; i < content.length; ++i) { for (var i = 0; i < content.length; ++i) {
var contentElement = content.queryElementAt(i, Ci.nsIWritablePropertyBag2); var contentElement = content[i];
// media:content don't require url, but if it's not there, we should // media:content don't require url, but if it's not there, we should
// skip it. // skip it.
if (!bagHasKey(contentElement, "url")) { if (!contentElement.url) {
continue; continue;
} }
var enc = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2); var enc = {};
// copy media:content bits over to equivalent enclosure bits // copy media:content bits over to equivalent enclosure bits
enc.setPropertyAsAString("url", contentElement.getPropertyAsAString("url")); enc.url = contentElement.url;
if (bagHasKey(contentElement, "type")) { if (contentElement.type) {
enc.setPropertyAsAString("type", contentElement.getPropertyAsAString("type")); enc.type = contentElement.type;
} }
else if (mediaType == "mediathumbnail") { else if (mediaType == "mediathumbnail") {
// thumbnails won't have a type, but default to image types // thumbnails won't have a type, but default to image types
enc.setPropertyAsAString("type", "image/*"); enc.type = "image/*";
enc.setPropertyAsBool("thumbnail", true); enc.thumbnail = true;
} }
if (bagHasKey(contentElement, "fileSize")) { if (contentElement.fileSize) {
enc.setPropertyAsAString("length", contentElement.getPropertyAsAString("fileSize")); enc.length = contentElement.fileSize;
} }
this._addToEnclosures(enc); this._addToEnclosures(enc);
@ -721,11 +690,7 @@ function fieldsToObj(container, fields) {
props = searchList[i]; props = searchList[i];
prop = null; prop = null;
field = isArray(props) ? props[0] : props; field = isArray(props) ? props[0] : props;
try { prop = container.fields[field];
prop = container.fields.getProperty(field);
}
catch (e) {
}
if (prop) { if (prop) {
prop = isArray(props) ? props[1](prop) : prop; prop = isArray(props) ? props[1](prop) : prop;
container[key] = prop; container[key] = prop;
@ -734,39 +699,27 @@ function fieldsToObj(container, fields) {
} }
} }
/**
* Lower cases an element's localName property
* @param element A DOM element.
*
* @returns The lower case localName property of the specified element
*/
function LC(element) {
return element.localName.toLowerCase();
}
// TODO move these post-processor functions
// create a generator element // create a generator element
function atomGenerator(s, generator) { function atomGenerator(s, generator) {
generator.QueryInterface(Ci.nsIFeedGenerator);
generator.agent = s.trim(); generator.agent = s.trim();
return generator; return generator;
} }
// post-process atom:logo to create an RSS2-like structure // post-process atom:logo to create an RSS2-like structure
function atomLogo(s, logo) { function atomLogo(s, logo) {
logo.setPropertyAsAString("url", s.trim()); logo.url = s.trim();
} }
// post-process an RSS category, map it to the Atom fields. // post-process an RSS category, map it to the Atom fields.
function rssCatTerm(s, cat) { function rssCatTerm(s, cat) {
// add slash handling? // add slash handling?
cat.setPropertyAsAString("term", s.trim()); cat.term = s.trim();
return cat; return cat;
} }
// post-process a GUID // post-process a GUID
function rssGuid(s, guid) { function rssGuid(s, guid) {
guid.setPropertyAsAString("guid", s.trim()); guid.guid = s.trim();
return guid; return guid;
} }
@ -784,7 +737,6 @@ function rssGuid(s, guid) {
// fields. // fields.
// //
function rssAuthor(s, author) { function rssAuthor(s, author) {
author.QueryInterface(Ci.nsIFeedPerson);
// check for RSS2 string format // check for RSS2 string format
var chars = s.trim(); var chars = s.trim();
var matches = chars.match(/(.*)\((.*)\)/); var matches = chars.match(/(.*)\((.*)\)/);
@ -818,17 +770,6 @@ function rssAuthor(s, author) {
return author; return author;
} }
//
// skipHours and skipDays map to arrays, so we need to change the
// string to an nsISupports in order to stick it in there.
//
function rssArrayElement(s) {
var str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
str.data = s;
str.QueryInterface(Ci.nsISupportsString);
return str;
}
/** /**
* Tries parsing a string through the JavaScript Date object. * Tries parsing a string through the JavaScript Date object.
* @param aDateString * @param aDateString
@ -1045,7 +986,7 @@ function WrapperElementInfo(fieldName) {
function FeedProcessor() { function FeedProcessor() {
this._reader = Cc[SAX_CONTRACTID].createInstance(Ci.nsISAXXMLReader); this._reader = Cc[SAX_CONTRACTID].createInstance(Ci.nsISAXXMLReader);
this._buf = ""; this._buf = "";
this._feed = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2); this._feed = {};
this._handlerStack = []; this._handlerStack = [];
this._xmlBaseStack = []; // sparse array keyed to nesting depth this._xmlBaseStack = []; // sparse array keyed to nesting depth
this._depth = 0; this._depth = 0;
@ -1129,11 +1070,11 @@ function FeedProcessor() {
}, },
"IN_SKIPDAYS": { "IN_SKIPDAYS": {
"day": new ElementInfo("days", null, rssArrayElement, true), "day": new ElementInfo("days", null, null, true),
}, },
"IN_SKIPHOURS": { "IN_SKIPHOURS": {
"hour": new ElementInfo("hours", null, rssArrayElement, true), "hour": new ElementInfo("hours", null, null, true),
}, },
"IN_MEDIAGROUP": { "IN_MEDIAGROUP": {
@ -1476,7 +1417,7 @@ FeedProcessor.prototype = {
obj.attributes = attributes; // just set the SAX attributes obj.attributes = attributes; // just set the SAX attributes
} }
else { else {
obj = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2); obj = {};
this._mapAttributes(obj, attributes); this._mapAttributes(obj, attributes);
} }
@ -1489,27 +1430,15 @@ FeedProcessor.prototype = {
var container = this._stack[this._stack.length - 1][0]; var container = this._stack[this._stack.length - 1][0];
// Check to see if it has the property // Check to see if it has the property
var prop; var prop = container[elementInfo.fieldName];
try {
prop = container.getProperty(elementInfo.fieldName);
}
catch (e) {
}
if (elementInfo.isArray) { if (elementInfo.isArray) {
if (!prop) { if (!prop) {
container.setPropertyAsInterface( container[elementInfo.fieldName] = [];
elementInfo.fieldName,
Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray),
);
} }
newProp = container.getProperty(elementInfo.fieldName); newProp = container[elementInfo.fieldName];
// XXX This QI should not be necessary, but XPConnect seems to fly newProp.push(obj);
// off the handle in the browser, and loses track of the interface
// on large files. Bug 335638.
newProp.QueryInterface(Ci.nsIMutableArray);
newProp.appendElement(obj);
// If new object is an nsIFeedContainer, we want to deal with // If new object is an nsIFeedContainer, we want to deal with
// its member nsIPropertyBag instead. // its member nsIPropertyBag instead.
@ -1520,9 +1449,9 @@ FeedProcessor.prototype = {
else { else {
// If it doesn't, set it. // If it doesn't, set it.
if (!prop) { if (!prop) {
container.setPropertyAsInterface(elementInfo.fieldName, obj); container[elementInfo.fieldName] = obj;
} }
newProp = container.getProperty(elementInfo.fieldName); newProp = container[elementInfo.fieldName];
} }
// make our new state name, and push the property onto the stack // make our new state name, and push the property onto the stack
@ -1545,7 +1474,7 @@ FeedProcessor.prototype = {
// If it's an array and we have to post-process, // If it's an array and we have to post-process,
// grab the last element // grab the last element
if (isArray) { if (isArray) {
element = container.queryElementAt(container.length - 1, Ci.nsISupports); element = container[container.length - 1];
} }
else { else {
element = container; element = container;
@ -1564,7 +1493,7 @@ FeedProcessor.prototype = {
// If it's an array, re-set the last element // If it's an array, re-set the last element
if (isArray) { if (isArray) {
container.replaceElementAt(element, container.length - 1); container[container.length - 1] = element;
} }
}, },
@ -1588,7 +1517,7 @@ FeedProcessor.prototype = {
for (var i = 0; i < attributes.length; ++i) { for (var i = 0; i < attributes.length; ++i) {
var key = this._prefixForNS(attributes.getURI(i)) + attributes.getLocalName(i); var key = this._prefixForNS(attributes.getURI(i)) + attributes.getLocalName(i);
var val = attributes.getValue(i); var val = attributes.getValue(i);
bag.setPropertyAsAString(key, val); bag[key] = val;
} }
}, },
@ -1638,13 +1567,8 @@ FeedProcessor.prototype = {
var contract = this._handlerStack[this._depth].containerClass; var contract = this._handlerStack[this._depth].containerClass;
// check if it's something specific, but not an entry // check if it's something specific, but not an entry
if (contract && contract != Entry) { if (contract && contract != Entry) {
var el = container.queryElementAt(container.length - 1, var el = container[container.length - 1];
Ci.nsIFeedElementBase); if (contract != Person) {
// XXX there must be a way to flatten these interfaces
if (contract == Person) {
el.QueryInterface(Ci.nsIFeedPerson);
}
else {
return; // don't know about this interface return; // don't know about this interface
} }
@ -1679,7 +1603,7 @@ FeedProcessor.prototype = {
// the rest of the function deals with entry- and feed-level stuff // the rest of the function deals with entry- and feed-level stuff
return; return;
} }
container = container.queryElementAt(container.length - 1, Ci.nsIWritablePropertyBag2); container = container[container.length - 1];
} }
// Make the buffer our new property // Make the buffer our new property
@ -1716,10 +1640,10 @@ FeedProcessor.prototype = {
} }
newProp.type = type; newProp.type = type;
newProp.base = this._xmlBaseStack[this._xmlBaseStack.length - 1]; newProp.base = this._xmlBaseStack[this._xmlBaseStack.length - 1];
container.setPropertyAsInterface(propName, newProp); container[propName] = newProp;
} }
else { else {
container.setPropertyAsAString(propName, chars); container[propName] = chars;
} }
}, },
@ -1743,7 +1667,7 @@ FeedProcessor.prototype = {
newProp.text = chars; newProp.text = chars;
newProp.type = "xhtml"; newProp.type = "xhtml";
newProp.base = this._xmlBaseStack[this._xmlBaseStack.length - 1]; newProp.base = this._xmlBaseStack[this._xmlBaseStack.length - 1];
container.setPropertyAsInterface(this._prefixForNS(uri) + localName, newProp); container[this._prefixForNS(uri) + localName] = newProp;
// XHTML will cause us to peek too far. The XHTML handler will // XHTML will cause us to peek too far. The XHTML handler will
// send us an end element to call. RFC4287-valid feeds allow a // send us an end element to call. RFC4287-valid feeds allow a