Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 022ee2d707
Fetching contributors…

Cannot retrieve contributors at this time

file 146 lines (112 sloc) 5.034 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
import types
from rdflib import Graph, URIRef
from rdflib.exceptions import ParserError
from StringIO import StringIO
from xml.sax import SAXParseException


class RDFException(Exception):
    """Exception thrown when the RDF parser encounters a problem."""

    def __init__(self, message=None, orig_exception=None):
        if message is None and orig_exception is not None:
            message = orig_exception.message

        super(RDFException, self).__init__(message)
        self.orig_exception = orig_exception

    def line(self):
        return (self.orig_exception.getLineNumber() if self.orig_exception else
                None)


class AddonRDFEntity(object):
    """
A "resolved" entity within an RDF file in an add-on. For use by SAX during
the entity resolution process.
"""

    def getByteStream(self):
        yield None

    def getSystemId(self):
        return ""


class AddonRDFEntityResolver(object):
    """
An entity resolver to be used by SAX for resolving internal entity
references.
"""

    def __init__(self, err):
        self.err = err

    def resolveEntity(self, public, system):
        if system.startswith("data:"):
            self.err.warning(
                    err_id=("rdf", "entity_resolver", "data_uri"),
                    warning="`data:` URIs are not permitted in `install.rdf`.",
                    filename="install.rdf")
        elif system.startswith("chrome://"):
            self.err.warning(
                    err_id=("rdf", "entity_resolver", "chrome_uri"),
                    warning="`chrome://` URI referenced before initialization.",
                    description="A chrome URI was referenced before the "
                                "browser chrome was initialized.",
                    filename="install.rdf")
        else:
            self.err.warning(
                    err_id=("rdf", "entity_resolver", "remote_uri"),
                    warning="Remote URI referenced from `install.rdf`.",
                    description="Remote URIs should not be used within "
                                "`install.rdf` files.",
                    filename="install.rdf")

        return AddonRDFEntity()


class RDFParser(object):
    """Parser wrapper for RDF files."""

    def __init__(self, err, data, namespace=None):
        self.err = err
        self.manifest = u"urn:mozilla:install-manifest"
        self.namespace = namespace or "http://www.mozilla.org/2004/em-rdf"

        if isinstance(data, types.StringTypes):
            data = StringIO(data) # Wrap data in a pseudo-file

        from rdflib.plugins.parsers import rdfxml
        orig_create_parser = rdfxml.create_parser

        try:
            # Patch rdflib to not resolve URL entities.
            def create_parser(*args, **kwargs):
                parser = orig_create_parser(*args, **kwargs)
                parser.setEntityResolver(AddonRDFEntityResolver(err))
                return parser
            rdfxml.create_parser = create_parser

            # Load up and parse the file in XML format.
            graph = Graph()
            graph.parse(data, format="xml")
            self.rdf = graph

        except ParserError as ex:
            # Re-raise the exception in a local exception type.
            raise RDFException(message=ex.message)
        except SAXParseException as ex:
            # Raise the SAX parse exceptions so we get some line info.
            raise RDFException(orig_exception=ex)
        finally:
            # If we fail, we don't want to sully up the creation function.
            rdfxml.create_parser = orig_create_parser

    def uri(self, element, namespace=None):
        "Returns a URIRef object for use with the RDF document."

        if namespace is None:
            namespace = self.namespace

        return URIRef("%s#%s" % (namespace, element))

    def get_root_subject(self):
        "Returns the BNode which describes the topmost subject of the graph."

        manifest = URIRef(self.manifest)

        if list(self.rdf.triples((manifest, None, None))):
            return manifest
        else:
            return self.rdf.subjects(None, self.manifest).next()

    def get_object(self, subject=None, predicate=None):
        """Eliminates some of the glue code for searching RDF. Pass
in a URIRef object (generated by the `uri` function above or
a BNode object (returned by this function) for either of the
parameters."""

        # Get the result of the search
        results = self.rdf.objects(subject, predicate)
        as_list = list(results)

        # Don't raise exceptions, value test!
        if not as_list:
            return None

        return as_list[0]

    def get_objects(self, subject=None, predicate=None):
        """Same as get_object, except returns a list of objects which
satisfy the query rather than a single result."""

        # Get the result of the search
        results = self.rdf.objects(subject, predicate)
        return list(results)
Something went wrong with that request. Please try again.