Blame src/lxml/saxparser.pxi

rpm-build d9acb6
# SAX-like interfaces
rpm-build d9acb6
rpm-build d9acb6
ctypedef enum _SaxParserEvents:
rpm-build d9acb6
    SAX_EVENT_START   =  1
rpm-build d9acb6
    SAX_EVENT_END     =  2
rpm-build d9acb6
    SAX_EVENT_DATA    =  4
rpm-build d9acb6
    SAX_EVENT_DOCTYPE =  8
rpm-build d9acb6
    SAX_EVENT_PI      = 16
rpm-build d9acb6
    SAX_EVENT_COMMENT = 32
rpm-build d9acb6
rpm-build d9acb6
ctypedef enum _ParseEventFilter:
rpm-build d9acb6
    PARSE_EVENT_FILTER_START     =  1
rpm-build d9acb6
    PARSE_EVENT_FILTER_END       =  2
rpm-build d9acb6
    PARSE_EVENT_FILTER_START_NS  =  4
rpm-build d9acb6
    PARSE_EVENT_FILTER_END_NS    =  8
rpm-build d9acb6
    PARSE_EVENT_FILTER_COMMENT   = 16
rpm-build d9acb6
    PARSE_EVENT_FILTER_PI        = 32
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef int _buildParseEventFilter(events) except -1:
rpm-build d9acb6
    cdef int event_filter
rpm-build d9acb6
    event_filter = 0
rpm-build d9acb6
    for event in events:
rpm-build d9acb6
        if event == 'start':
rpm-build d9acb6
            event_filter |= PARSE_EVENT_FILTER_START
rpm-build d9acb6
        elif event == 'end':
rpm-build d9acb6
            event_filter |= PARSE_EVENT_FILTER_END
rpm-build d9acb6
        elif event == 'start-ns':
rpm-build d9acb6
            event_filter |= PARSE_EVENT_FILTER_START_NS
rpm-build d9acb6
        elif event == 'end-ns':
rpm-build d9acb6
            event_filter |= PARSE_EVENT_FILTER_END_NS
rpm-build d9acb6
        elif event == 'comment':
rpm-build d9acb6
            event_filter |= PARSE_EVENT_FILTER_COMMENT
rpm-build d9acb6
        elif event == 'pi':
rpm-build d9acb6
            event_filter |= PARSE_EVENT_FILTER_PI
rpm-build d9acb6
        else:
rpm-build d9acb6
            raise ValueError, f"invalid event name '{event}'"
rpm-build d9acb6
    return event_filter
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef class _SaxParserTarget:
rpm-build d9acb6
    cdef int _sax_event_filter
rpm-build d9acb6
    def __cinit__(self):
rpm-build d9acb6
        self._sax_event_filter = 0
rpm-build d9acb6
rpm-build d9acb6
    cdef _handleSaxStart(self, tag, attrib, nsmap):
rpm-build d9acb6
        return None
rpm-build d9acb6
    cdef _handleSaxEnd(self, tag):
rpm-build d9acb6
        return None
rpm-build d9acb6
    cdef int _handleSaxData(self, data) except -1:
rpm-build d9acb6
        return 0
rpm-build d9acb6
    cdef int _handleSaxDoctype(self, root_tag, public_id, system_id) except -1:
rpm-build d9acb6
        return 0
rpm-build d9acb6
    cdef _handleSaxPi(self, target, data):
rpm-build d9acb6
        return None
rpm-build d9acb6
    cdef _handleSaxComment(self, comment):
rpm-build d9acb6
        return None
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
#@cython.final
rpm-build d9acb6
@cython.internal
rpm-build d9acb6
@cython.no_gc_clear  # Required because parent class uses it - Cython bug.
rpm-build d9acb6
cdef class _SaxParserContext(_ParserContext):
rpm-build d9acb6
    u"""This class maps SAX2 events to parser target events.
rpm-build d9acb6
    """
rpm-build d9acb6
    cdef _SaxParserTarget _target
rpm-build d9acb6
    cdef _BaseParser _parser
rpm-build d9acb6
    cdef xmlparser.startElementNsSAX2Func _origSaxStart
rpm-build d9acb6
    cdef xmlparser.endElementNsSAX2Func   _origSaxEnd
rpm-build d9acb6
    cdef xmlparser.startElementSAXFunc    _origSaxStartNoNs
rpm-build d9acb6
    cdef xmlparser.endElementSAXFunc      _origSaxEndNoNs
rpm-build d9acb6
    cdef xmlparser.charactersSAXFunc      _origSaxData
rpm-build d9acb6
    cdef xmlparser.cdataBlockSAXFunc      _origSaxCData
rpm-build d9acb6
    cdef xmlparser.internalSubsetSAXFunc  _origSaxDoctype
rpm-build d9acb6
    cdef xmlparser.commentSAXFunc         _origSaxComment
rpm-build d9acb6
    cdef xmlparser.processingInstructionSAXFunc _origSaxPI
rpm-build d9acb6
    cdef xmlparser.startDocumentSAXFunc   _origSaxStartDocument
rpm-build d9acb6
rpm-build d9acb6
    # for event collecting
rpm-build d9acb6
    cdef int _event_filter
rpm-build d9acb6
    cdef list _ns_stack
rpm-build d9acb6
    cdef list _node_stack
rpm-build d9acb6
    cdef _ParseEventsIterator events_iterator
rpm-build d9acb6
rpm-build d9acb6
    # for iterparse
rpm-build d9acb6
    cdef _Element  _root
rpm-build d9acb6
    cdef _MultiTagMatcher _matcher
rpm-build d9acb6
rpm-build d9acb6
    def __cinit__(self, _BaseParser parser):
rpm-build d9acb6
        self._ns_stack = []
rpm-build d9acb6
        self._node_stack = []
rpm-build d9acb6
        self._parser = parser
rpm-build d9acb6
        self.events_iterator = _ParseEventsIterator()
rpm-build d9acb6
rpm-build d9acb6
    cdef void _setSaxParserTarget(self, _SaxParserTarget target):
rpm-build d9acb6
        self._target = target
rpm-build d9acb6
rpm-build d9acb6
    cdef void _initParserContext(self, xmlparser.xmlParserCtxt* c_ctxt):
rpm-build d9acb6
        _ParserContext._initParserContext(self, c_ctxt)
rpm-build d9acb6
        if self._target is not None:
rpm-build d9acb6
            self._connectTarget(c_ctxt)
rpm-build d9acb6
        elif self._event_filter:
rpm-build d9acb6
            self._connectEvents(c_ctxt)
rpm-build d9acb6
rpm-build d9acb6
    cdef void _connectTarget(self, xmlparser.xmlParserCtxt* c_ctxt):
rpm-build d9acb6
        """wrap original SAX2 callbacks to call into parser target"""
rpm-build d9acb6
        sax = c_ctxt.sax
rpm-build d9acb6
        self._origSaxStart = sax.startElementNs = NULL
rpm-build d9acb6
        self._origSaxStartNoNs = sax.startElement = NULL
rpm-build d9acb6
        if self._target._sax_event_filter & SAX_EVENT_START:
rpm-build d9acb6
            # intercept => overwrite orig callback
rpm-build d9acb6
            # FIXME: also intercept on when collecting END events
rpm-build d9acb6
            if sax.initialized == xmlparser.XML_SAX2_MAGIC:
rpm-build d9acb6
                sax.startElementNs = _handleSaxTargetStart
rpm-build d9acb6
            sax.startElement = _handleSaxTargetStartNoNs
rpm-build d9acb6
rpm-build d9acb6
        self._origSaxEnd = sax.endElementNs = NULL
rpm-build d9acb6
        self._origSaxEndNoNs = sax.endElement = NULL
rpm-build d9acb6
        if self._target._sax_event_filter & SAX_EVENT_END:
rpm-build d9acb6
            if sax.initialized == xmlparser.XML_SAX2_MAGIC:
rpm-build d9acb6
                sax.endElementNs = _handleSaxEnd
rpm-build d9acb6
            sax.endElement = _handleSaxEndNoNs
rpm-build d9acb6
rpm-build d9acb6
        self._origSaxData = sax.characters = sax.cdataBlock = NULL
rpm-build d9acb6
        if self._target._sax_event_filter & SAX_EVENT_DATA:
rpm-build d9acb6
            sax.characters = sax.cdataBlock = _handleSaxData
rpm-build d9acb6
rpm-build d9acb6
        # doctype propagation is always required for entity replacement
rpm-build d9acb6
        self._origSaxDoctype = sax.internalSubset
rpm-build d9acb6
        if self._target._sax_event_filter & SAX_EVENT_DOCTYPE:
rpm-build d9acb6
            sax.internalSubset = _handleSaxTargetDoctype
rpm-build d9acb6
rpm-build d9acb6
        self._origSaxPI = sax.processingInstruction = NULL
rpm-build d9acb6
        if self._target._sax_event_filter & SAX_EVENT_PI:
rpm-build d9acb6
            sax.processingInstruction = _handleSaxPI
rpm-build d9acb6
rpm-build d9acb6
        self._origSaxComment = sax.comment = NULL
rpm-build d9acb6
        if self._target._sax_event_filter & SAX_EVENT_COMMENT:
rpm-build d9acb6
            sax.comment = _handleSaxTargetComment
rpm-build d9acb6
rpm-build d9acb6
        # enforce entity replacement
rpm-build d9acb6
        sax.reference = NULL
rpm-build d9acb6
        c_ctxt.replaceEntities = 1
rpm-build d9acb6
rpm-build d9acb6
    cdef void _connectEvents(self, xmlparser.xmlParserCtxt* c_ctxt):
rpm-build d9acb6
        """wrap original SAX2 callbacks to collect parse events"""
rpm-build d9acb6
        sax = c_ctxt.sax
rpm-build d9acb6
        self._origSaxStartDocument = sax.startDocument
rpm-build d9acb6
        sax.startDocument = _handleSaxStartDocument
rpm-build d9acb6
        self._origSaxStart = sax.startElementNs
rpm-build d9acb6
        self._origSaxStartNoNs = sax.startElement
rpm-build d9acb6
        # only override start event handler if needed
rpm-build d9acb6
        if self._event_filter == 0 or \
rpm-build d9acb6
               self._event_filter & (PARSE_EVENT_FILTER_START |
rpm-build d9acb6
                                     PARSE_EVENT_FILTER_END |
rpm-build d9acb6
                                     PARSE_EVENT_FILTER_START_NS |
rpm-build d9acb6
                                     PARSE_EVENT_FILTER_END_NS):
rpm-build d9acb6
            sax.startElementNs = <xmlparser.startElementNsSAX2Func>_handleSaxStart
rpm-build d9acb6
            sax.startElement = <xmlparser.startElementSAXFunc>_handleSaxStartNoNs
rpm-build d9acb6
rpm-build d9acb6
        self._origSaxEnd = sax.endElementNs
rpm-build d9acb6
        self._origSaxEndNoNs = sax.endElement
rpm-build d9acb6
        # only override end event handler if needed
rpm-build d9acb6
        if self._event_filter == 0 or \
rpm-build d9acb6
               self._event_filter & (PARSE_EVENT_FILTER_END |
rpm-build d9acb6
                                     PARSE_EVENT_FILTER_END_NS):
rpm-build d9acb6
            sax.endElementNs = <xmlparser.endElementNsSAX2Func>_handleSaxEnd
rpm-build d9acb6
            sax.endElement = <xmlparser.endElementSAXFunc>_handleSaxEndNoNs
rpm-build d9acb6
rpm-build d9acb6
        self._origSaxComment = sax.comment
rpm-build d9acb6
        if self._event_filter & PARSE_EVENT_FILTER_COMMENT:
rpm-build d9acb6
            sax.comment = <xmlparser.commentSAXFunc>_handleSaxComment
rpm-build d9acb6
rpm-build d9acb6
        self._origSaxPI = sax.processingInstruction
rpm-build d9acb6
        if self._event_filter & PARSE_EVENT_FILTER_PI:
rpm-build d9acb6
            sax.processingInstruction = <xmlparser.processingInstructionSAXFunc>_handleSaxPIEvent
rpm-build d9acb6
rpm-build d9acb6
    cdef _setEventFilter(self, events, tag):
rpm-build d9acb6
        self._event_filter = _buildParseEventFilter(events)
rpm-build d9acb6
        if not self._event_filter or tag is None or tag == '*':
rpm-build d9acb6
            self._matcher = None
rpm-build d9acb6
        else:
rpm-build d9acb6
            self._matcher = _MultiTagMatcher.__new__(_MultiTagMatcher, tag)
rpm-build d9acb6
rpm-build d9acb6
    cdef int startDocument(self, xmlDoc* c_doc) except -1:
rpm-build d9acb6
        try:
rpm-build d9acb6
            self._doc = _documentFactory(c_doc, self._parser)
rpm-build d9acb6
        finally:
rpm-build d9acb6
            self._parser = None  # clear circular reference ASAP
rpm-build d9acb6
        if self._matcher is not None:
rpm-build d9acb6
            self._matcher.cacheTags(self._doc, True) # force entry in libxml2 dict
rpm-build d9acb6
        return 0
rpm-build d9acb6
rpm-build d9acb6
    cdef int pushEvent(self, event, xmlNode* c_node) except -1:
rpm-build d9acb6
        cdef _Element root
rpm-build d9acb6
        if self._root is None:
rpm-build d9acb6
            root = self._doc.getroot()
rpm-build d9acb6
            if root is not None and root._c_node.type == tree.XML_ELEMENT_NODE:
rpm-build d9acb6
                self._root = root
rpm-build d9acb6
        node = _elementFactory(self._doc, c_node)
rpm-build d9acb6
        self.events_iterator._events.append( (event, node) )
rpm-build d9acb6
        return 0
rpm-build d9acb6
rpm-build d9acb6
    cdef int flushEvents(self) except -1:
rpm-build d9acb6
        events = self.events_iterator._events
rpm-build d9acb6
        while self._node_stack:
rpm-build d9acb6
            events.append( ('end', self._node_stack.pop()) )
rpm-build d9acb6
            _pushSaxNsEndEvents(self)
rpm-build d9acb6
        while self._ns_stack:
rpm-build d9acb6
            _pushSaxNsEndEvents(self)
rpm-build d9acb6
rpm-build d9acb6
    cdef void _handleSaxException(self, xmlparser.xmlParserCtxt* c_ctxt):
rpm-build d9acb6
        if c_ctxt.errNo == xmlerror.XML_ERR_OK:
rpm-build d9acb6
            c_ctxt.errNo = xmlerror.XML_ERR_INTERNAL_ERROR
rpm-build d9acb6
        # stop parsing immediately
rpm-build d9acb6
        c_ctxt.wellFormed = 0
rpm-build d9acb6
        c_ctxt.disableSAX = 1
rpm-build d9acb6
        c_ctxt.instate = xmlparser.XML_PARSER_EOF
rpm-build d9acb6
        self._store_raised()
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
@cython.final
rpm-build d9acb6
@cython.internal
rpm-build d9acb6
cdef class _ParseEventsIterator:
rpm-build d9acb6
    """A reusable parse events iterator"""
rpm-build d9acb6
    cdef list _events
rpm-build d9acb6
    cdef int _event_index
rpm-build d9acb6
rpm-build d9acb6
    def __cinit__(self):
rpm-build d9acb6
        self._events = []
rpm-build d9acb6
        self._event_index = 0
rpm-build d9acb6
rpm-build d9acb6
    def __iter__(self):
rpm-build d9acb6
        return self
rpm-build d9acb6
rpm-build d9acb6
    def __next__(self):
rpm-build d9acb6
        cdef int event_index = self._event_index
rpm-build d9acb6
        events = self._events
rpm-build d9acb6
        if event_index >= 2**10 or event_index * 2 >= len(events):
rpm-build d9acb6
            if event_index:
rpm-build d9acb6
                # clean up from time to time
rpm-build d9acb6
                del events[:event_index]
rpm-build d9acb6
                self._event_index = event_index = 0
rpm-build d9acb6
            if event_index >= len(events):
rpm-build d9acb6
                raise StopIteration
rpm-build d9acb6
        item = events[event_index]
rpm-build d9acb6
        self._event_index = event_index + 1
rpm-build d9acb6
        return item
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef int _appendNsEvents(_SaxParserContext context, int c_nb_namespaces,
rpm-build d9acb6
                         const_xmlChar** c_namespaces) except -1:
rpm-build d9acb6
    cdef int i
rpm-build d9acb6
    for i in xrange(c_nb_namespaces):
rpm-build d9acb6
        ns_tuple = (funicodeOrEmpty(c_namespaces[0]),
rpm-build d9acb6
                    funicode(c_namespaces[1]))
rpm-build d9acb6
        context.events_iterator._events.append( ("start-ns", ns_tuple) )
rpm-build d9acb6
        c_namespaces += 2
rpm-build d9acb6
    return 0
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxStart(
rpm-build d9acb6
        void* ctxt, const_xmlChar* c_localname, const_xmlChar* c_prefix,
rpm-build d9acb6
        const_xmlChar* c_namespace, int c_nb_namespaces,
rpm-build d9acb6
        const_xmlChar** c_namespaces,
rpm-build d9acb6
        int c_nb_attributes, int c_nb_defaulted,
rpm-build d9acb6
        const_xmlChar** c_attributes) with gil:
rpm-build d9acb6
    cdef int i
rpm-build d9acb6
    cdef size_t c_len
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        if (c_nb_namespaces and
rpm-build d9acb6
                context._event_filter & PARSE_EVENT_FILTER_START_NS):
rpm-build d9acb6
            _appendNsEvents(context, c_nb_namespaces, c_namespaces)
rpm-build d9acb6
        context._origSaxStart(c_ctxt, c_localname, c_prefix, c_namespace,
rpm-build d9acb6
                              c_nb_namespaces, c_namespaces, c_nb_attributes,
rpm-build d9acb6
                              c_nb_defaulted, c_attributes)
rpm-build d9acb6
        if c_ctxt.html:
rpm-build d9acb6
            _fixHtmlDictNodeNames(c_ctxt.dict, c_ctxt.node)
rpm-build d9acb6
rpm-build d9acb6
        if context._event_filter & PARSE_EVENT_FILTER_END_NS:
rpm-build d9acb6
            context._ns_stack.append(c_nb_namespaces)
rpm-build d9acb6
        if context._event_filter & (PARSE_EVENT_FILTER_END |
rpm-build d9acb6
                                    PARSE_EVENT_FILTER_START):
rpm-build d9acb6
            _pushSaxStartEvent(context, c_ctxt, c_namespace,
rpm-build d9acb6
                               c_localname, None)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxTargetStart(
rpm-build d9acb6
        void* ctxt, const_xmlChar* c_localname, const_xmlChar* c_prefix,
rpm-build d9acb6
        const_xmlChar* c_namespace, int c_nb_namespaces,
rpm-build d9acb6
        const_xmlChar** c_namespaces,
rpm-build d9acb6
        int c_nb_attributes, int c_nb_defaulted,
rpm-build d9acb6
        const_xmlChar** c_attributes) with gil:
rpm-build d9acb6
    cdef int i
rpm-build d9acb6
    cdef size_t c_len
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        if (c_nb_namespaces and
rpm-build d9acb6
                context._event_filter & PARSE_EVENT_FILTER_START_NS):
rpm-build d9acb6
            _appendNsEvents(context, c_nb_namespaces, c_namespaces)
rpm-build d9acb6
        if c_nb_defaulted > 0:
rpm-build d9acb6
            # only add default attributes if we asked for them
rpm-build d9acb6
            if c_ctxt.loadsubset & xmlparser.XML_COMPLETE_ATTRS == 0:
rpm-build d9acb6
                c_nb_attributes -= c_nb_defaulted
rpm-build d9acb6
        if c_nb_attributes == 0:
rpm-build d9acb6
            attrib = IMMUTABLE_EMPTY_MAPPING
rpm-build d9acb6
        else:
rpm-build d9acb6
            attrib = {}
rpm-build d9acb6
            for i in xrange(c_nb_attributes):
rpm-build d9acb6
                name = _namespacedNameFromNsName(
rpm-build d9acb6
                    c_attributes[2], c_attributes[0])
rpm-build d9acb6
                if c_attributes[3] is NULL:
rpm-build d9acb6
                    value = ''
rpm-build d9acb6
                else:
rpm-build d9acb6
                    c_len = c_attributes[4] - c_attributes[3]
rpm-build d9acb6
                    value = c_attributes[3][:c_len].decode('utf8')
rpm-build d9acb6
                attrib[name] = value
rpm-build d9acb6
                c_attributes += 5
rpm-build d9acb6
        if c_nb_namespaces == 0:
rpm-build d9acb6
            nsmap = IMMUTABLE_EMPTY_MAPPING
rpm-build d9acb6
        else:
rpm-build d9acb6
            nsmap = {}
rpm-build d9acb6
            for i in xrange(c_nb_namespaces):
rpm-build d9acb6
                prefix = funicodeOrNone(c_namespaces[0])
rpm-build d9acb6
                nsmap[prefix] = funicode(c_namespaces[1])
rpm-build d9acb6
                c_namespaces += 2
rpm-build d9acb6
        element = _callTargetSaxStart(
rpm-build d9acb6
            context, c_ctxt,
rpm-build d9acb6
            _namespacedNameFromNsName(c_namespace, c_localname),
rpm-build d9acb6
            attrib, nsmap)
rpm-build d9acb6
rpm-build d9acb6
        if context._event_filter & PARSE_EVENT_FILTER_END_NS:
rpm-build d9acb6
            context._ns_stack.append(c_nb_namespaces)
rpm-build d9acb6
        if context._event_filter & (PARSE_EVENT_FILTER_END |
rpm-build d9acb6
                                    PARSE_EVENT_FILTER_START):
rpm-build d9acb6
            _pushSaxStartEvent(context, c_ctxt, c_namespace,
rpm-build d9acb6
                               c_localname, element)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxStartNoNs(void* ctxt, const_xmlChar* c_name,
rpm-build d9acb6
                              const_xmlChar** c_attributes) with gil:
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        context._origSaxStartNoNs(c_ctxt, c_name, c_attributes)
rpm-build d9acb6
        if c_ctxt.html:
rpm-build d9acb6
            _fixHtmlDictNodeNames(c_ctxt.dict, c_ctxt.node)
rpm-build d9acb6
        if context._event_filter & (PARSE_EVENT_FILTER_END |
rpm-build d9acb6
                                    PARSE_EVENT_FILTER_START):
rpm-build d9acb6
            _pushSaxStartEvent(context, c_ctxt, NULL, c_name, None)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxTargetStartNoNs(void* ctxt, const_xmlChar* c_name,
rpm-build d9acb6
                                    const_xmlChar** c_attributes) with gil:
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        if c_attributes is NULL:
rpm-build d9acb6
            attrib = IMMUTABLE_EMPTY_MAPPING
rpm-build d9acb6
        else:
rpm-build d9acb6
            attrib = {}
rpm-build d9acb6
            while c_attributes[0] is not NULL:
rpm-build d9acb6
                name = funicode(c_attributes[0])
rpm-build d9acb6
                attrib[name] = funicodeOrEmpty(c_attributes[1])
rpm-build d9acb6
                c_attributes += 2
rpm-build d9acb6
        element = _callTargetSaxStart(
rpm-build d9acb6
            context, c_ctxt, funicode(c_name),
rpm-build d9acb6
            attrib, IMMUTABLE_EMPTY_MAPPING)
rpm-build d9acb6
        if context._event_filter & (PARSE_EVENT_FILTER_END |
rpm-build d9acb6
                                    PARSE_EVENT_FILTER_START):
rpm-build d9acb6
            _pushSaxStartEvent(context, c_ctxt, NULL, c_name, element)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef _callTargetSaxStart(_SaxParserContext context,
rpm-build d9acb6
                         xmlparser.xmlParserCtxt* c_ctxt,
rpm-build d9acb6
                         tag, attrib, nsmap):
rpm-build d9acb6
    element = context._target._handleSaxStart(tag, attrib, nsmap)
rpm-build d9acb6
    if element is not None and c_ctxt.input is not NULL:
rpm-build d9acb6
        if isinstance(element, _Element):
rpm-build d9acb6
            (<_Element>element)._c_node.line = (
rpm-build d9acb6
                <unsigned short>c_ctxt.input.line
rpm-build d9acb6
                if c_ctxt.input.line < 65535 else 65535)
rpm-build d9acb6
    return element
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef int _pushSaxStartEvent(_SaxParserContext context,
rpm-build d9acb6
                            xmlparser.xmlParserCtxt* c_ctxt,
rpm-build d9acb6
                            const_xmlChar* c_href,
rpm-build d9acb6
                            const_xmlChar* c_name, node) except -1:
rpm-build d9acb6
    if (context._matcher is None or
rpm-build d9acb6
            context._matcher.matchesNsTag(c_href, c_name)):
rpm-build d9acb6
        if node is None and context._target is None:
rpm-build d9acb6
            assert context._doc is not None
rpm-build d9acb6
            node = _elementFactory(context._doc, c_ctxt.node)
rpm-build d9acb6
        if context._event_filter & PARSE_EVENT_FILTER_START:
rpm-build d9acb6
            context.events_iterator._events.append(('start', node))
rpm-build d9acb6
        if (context._target is None and
rpm-build d9acb6
                context._event_filter & PARSE_EVENT_FILTER_END):
rpm-build d9acb6
            context._node_stack.append(node)
rpm-build d9acb6
    return 0
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxEnd(void* ctxt, const_xmlChar* c_localname,
rpm-build d9acb6
                        const_xmlChar* c_prefix,
rpm-build d9acb6
                        const_xmlChar* c_namespace) with gil:
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        if context._target is not None:
rpm-build d9acb6
            node = context._target._handleSaxEnd(
rpm-build d9acb6
                _namespacedNameFromNsName(c_namespace, c_localname))
rpm-build d9acb6
        else:
rpm-build d9acb6
            context._origSaxEnd(c_ctxt, c_localname, c_prefix, c_namespace)
rpm-build d9acb6
            node = None
rpm-build d9acb6
        _pushSaxEndEvent(context, c_namespace, c_localname, node)
rpm-build d9acb6
        _pushSaxNsEndEvents(context)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxEndNoNs(void* ctxt, const_xmlChar* c_name) with gil:
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        if context._target is not None:
rpm-build d9acb6
            node = context._target._handleSaxEnd(funicode(c_name))
rpm-build d9acb6
        else:
rpm-build d9acb6
            context._origSaxEndNoNs(c_ctxt, c_name)
rpm-build d9acb6
            node = None
rpm-build d9acb6
        _pushSaxEndEvent(context, NULL, c_name, node)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef tuple NS_END_EVENT = ('end-ns', None)
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef int _pushSaxNsEndEvents(_SaxParserContext context) except -1:
rpm-build d9acb6
    cdef int i
rpm-build d9acb6
    if context._event_filter & PARSE_EVENT_FILTER_END_NS:
rpm-build d9acb6
        for i in range(context._ns_stack.pop()):
rpm-build d9acb6
            context.events_iterator._events.append(NS_END_EVENT)
rpm-build d9acb6
    return 0
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef int _pushSaxEndEvent(_SaxParserContext context,
rpm-build d9acb6
                          const_xmlChar* c_href,
rpm-build d9acb6
                          const_xmlChar* c_name, node) except -1:
rpm-build d9acb6
    if context._event_filter & PARSE_EVENT_FILTER_END:
rpm-build d9acb6
        if (context._matcher is None or
rpm-build d9acb6
                context._matcher.matchesNsTag(c_href, c_name)):
rpm-build d9acb6
            if context._target is None:
rpm-build d9acb6
                node = context._node_stack.pop()
rpm-build d9acb6
            context.events_iterator._events.append(('end', node))
rpm-build d9acb6
    return 0
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxData(void* ctxt, const_xmlChar* c_data, int data_len) with gil:
rpm-build d9acb6
    # can only be called if parsing with a target
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        context._target._handleSaxData(
rpm-build d9acb6
            c_data[:data_len].decode('utf8'))
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxTargetDoctype(void* ctxt, const_xmlChar* c_name,
rpm-build d9acb6
                                  const_xmlChar* c_public,
rpm-build d9acb6
                                  const_xmlChar* c_system) with gil:
rpm-build d9acb6
    # can only be called if parsing with a target
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        context._target._handleSaxDoctype(
rpm-build d9acb6
            funicodeOrNone(c_name),
rpm-build d9acb6
            funicodeOrNone(c_public),
rpm-build d9acb6
            funicodeOrNone(c_system))
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxStartDocument(void* ctxt) with gil:
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    context._origSaxStartDocument(ctxt)
rpm-build d9acb6
    c_doc = c_ctxt.myDoc
rpm-build d9acb6
    try:
rpm-build d9acb6
        context.startDocument(c_doc)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxPI(void* ctxt, const_xmlChar* c_target,
rpm-build d9acb6
                       const_xmlChar* c_data) with gil:
rpm-build d9acb6
    # can only be called if parsing with a target
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        pi = context._target._handleSaxPi(
rpm-build d9acb6
            funicodeOrNone(c_target),
rpm-build d9acb6
            funicodeOrEmpty(c_data))
rpm-build d9acb6
        if context._event_filter & PARSE_EVENT_FILTER_PI:
rpm-build d9acb6
            context.events_iterator._events.append(('pi', pi))
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxPIEvent(void* ctxt, const_xmlChar* target,
rpm-build d9acb6
                            const_xmlChar* data) with gil:
rpm-build d9acb6
    # can only be called when collecting pi events
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    context._origSaxPI(ctxt, target, data)
rpm-build d9acb6
    c_node = _findLastEventNode(c_ctxt)
rpm-build d9acb6
    if c_node is NULL:
rpm-build d9acb6
        return
rpm-build d9acb6
    try:
rpm-build d9acb6
        context.pushEvent('pi', c_node)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxTargetComment(void* ctxt, const_xmlChar* c_data) with gil:
rpm-build d9acb6
    # can only be called if parsing with a target
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    try:
rpm-build d9acb6
        comment = context._target._handleSaxComment(funicodeOrEmpty(c_data))
rpm-build d9acb6
        if context._event_filter & PARSE_EVENT_FILTER_COMMENT:
rpm-build d9acb6
            context.events_iterator._events.append(('comment', comment))
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef void _handleSaxComment(void* ctxt, const_xmlChar* text) with gil:
rpm-build d9acb6
    # can only be called when collecting comment events
rpm-build d9acb6
    c_ctxt = <xmlparser.xmlParserCtxt*>ctxt
rpm-build d9acb6
    if c_ctxt._private is NULL or c_ctxt.disableSAX:
rpm-build d9acb6
        return
rpm-build d9acb6
    context = <_SaxParserContext>c_ctxt._private
rpm-build d9acb6
    context._origSaxComment(ctxt, text)
rpm-build d9acb6
    c_node = _findLastEventNode(c_ctxt)
rpm-build d9acb6
    if c_node is NULL:
rpm-build d9acb6
        return
rpm-build d9acb6
    try:
rpm-build d9acb6
        context.pushEvent('comment', c_node)
rpm-build d9acb6
    except:
rpm-build d9acb6
        context._handleSaxException(c_ctxt)
rpm-build d9acb6
    finally:
rpm-build d9acb6
        return  # swallow any further exceptions
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
cdef inline xmlNode* _findLastEventNode(xmlparser.xmlParserCtxt* c_ctxt):
rpm-build d9acb6
    # this mimics what libxml2 creates for comments/PIs
rpm-build d9acb6
    if c_ctxt.inSubset == 1:
rpm-build d9acb6
        return c_ctxt.myDoc.intSubset.last
rpm-build d9acb6
    elif c_ctxt.inSubset == 2:
rpm-build d9acb6
        return c_ctxt.myDoc.extSubset.last
rpm-build d9acb6
    elif c_ctxt.node is NULL:
rpm-build d9acb6
        return c_ctxt.myDoc.last
rpm-build d9acb6
    elif c_ctxt.node.type == tree.XML_ELEMENT_NODE:
rpm-build d9acb6
        return c_ctxt.node.last
rpm-build d9acb6
    else:
rpm-build d9acb6
        return c_ctxt.node.next
rpm-build d9acb6
rpm-build d9acb6
rpm-build d9acb6
############################################################
rpm-build d9acb6
## ET compatible XML tree builder
rpm-build d9acb6
############################################################
rpm-build d9acb6
rpm-build d9acb6
cdef class TreeBuilder(_SaxParserTarget):
rpm-build d9acb6
    u"""TreeBuilder(self, element_factory=None, parser=None)
rpm-build d9acb6
    Parser target that builds a tree.
rpm-build d9acb6
rpm-build d9acb6
    The final tree is returned by the ``close()`` method.
rpm-build d9acb6
    """
rpm-build d9acb6
    cdef _BaseParser _parser
rpm-build d9acb6
    cdef object _factory
rpm-build d9acb6
    cdef list _data
rpm-build d9acb6
    cdef list _element_stack
rpm-build d9acb6
    cdef object _element_stack_pop
rpm-build d9acb6
    cdef _Element _last # may be None
rpm-build d9acb6
    cdef bint _in_tail
rpm-build d9acb6
rpm-build d9acb6
    def __init__(self, *, element_factory=None, parser=None):
rpm-build d9acb6
        self._sax_event_filter = \
rpm-build d9acb6
            SAX_EVENT_START | SAX_EVENT_END | SAX_EVENT_DATA | \
rpm-build d9acb6
            SAX_EVENT_PI | SAX_EVENT_COMMENT
rpm-build d9acb6
        self._data = [] # data collector
rpm-build d9acb6
        self._element_stack = [] # element stack
rpm-build d9acb6
        self._element_stack_pop = self._element_stack.pop
rpm-build d9acb6
        self._last = None # last element
rpm-build d9acb6
        self._in_tail = 0 # true if we're after an end tag
rpm-build d9acb6
        self._factory = element_factory
rpm-build d9acb6
        self._parser = parser
rpm-build d9acb6
rpm-build d9acb6
    @cython.final
rpm-build d9acb6
    cdef int _flush(self) except -1:
rpm-build d9acb6
        if self._data:
rpm-build d9acb6
            if self._last is not None:
rpm-build d9acb6
                text = u"".join(self._data)
rpm-build d9acb6
                if self._in_tail:
rpm-build d9acb6
                    assert self._last.tail is None, u"internal error (tail)"
rpm-build d9acb6
                    self._last.tail = text
rpm-build d9acb6
                else:
rpm-build d9acb6
                    assert self._last.text is None, u"internal error (text)"
rpm-build d9acb6
                    self._last.text = text
rpm-build d9acb6
            del self._data[:]
rpm-build d9acb6
        return 0
rpm-build d9acb6
rpm-build d9acb6
    # internal SAX event handlers
rpm-build d9acb6
rpm-build d9acb6
    @cython.final
rpm-build d9acb6
    cdef _handleSaxStart(self, tag, attrib, nsmap):
rpm-build d9acb6
        self._flush()
rpm-build d9acb6
        if self._factory is not None:
rpm-build d9acb6
            self._last = self._factory(tag, attrib)
rpm-build d9acb6
            if self._element_stack:
rpm-build d9acb6
                _appendChild(self._element_stack[-1], self._last)
rpm-build d9acb6
        elif self._element_stack:
rpm-build d9acb6
            self._last = _makeSubElement(
rpm-build d9acb6
                self._element_stack[-1], tag, None, None, attrib, nsmap, None)
rpm-build d9acb6
        else:
rpm-build d9acb6
            self._last = _makeElement(
rpm-build d9acb6
                tag, NULL, None, self._parser, None, None, attrib, nsmap, None)
rpm-build d9acb6
        self._element_stack.append(self._last)
rpm-build d9acb6
        self._in_tail = 0
rpm-build d9acb6
        return self._last
rpm-build d9acb6
rpm-build d9acb6
    @cython.final
rpm-build d9acb6
    cdef _handleSaxEnd(self, tag):
rpm-build d9acb6
        self._flush()
rpm-build d9acb6
        self._last = self._element_stack_pop()
rpm-build d9acb6
        self._in_tail = 1
rpm-build d9acb6
        return self._last
rpm-build d9acb6
rpm-build d9acb6
    @cython.final
rpm-build d9acb6
    cdef int _handleSaxData(self, data) except -1:
rpm-build d9acb6
        self._data.append(data)
rpm-build d9acb6
rpm-build d9acb6
    @cython.final
rpm-build d9acb6
    cdef _handleSaxPi(self, target, data):
rpm-build d9acb6
        self._flush()
rpm-build d9acb6
        self._last = ProcessingInstruction(target, data)
rpm-build d9acb6
        if self._element_stack:
rpm-build d9acb6
            _appendChild(self._element_stack[-1], self._last)
rpm-build d9acb6
        self._in_tail = 1
rpm-build d9acb6
        return self._last
rpm-build d9acb6
rpm-build d9acb6
    @cython.final
rpm-build d9acb6
    cdef _handleSaxComment(self, comment):
rpm-build d9acb6
        self._flush()
rpm-build d9acb6
        self._last = Comment(comment)
rpm-build d9acb6
        if self._element_stack:
rpm-build d9acb6
            _appendChild(self._element_stack[-1], self._last)
rpm-build d9acb6
        self._in_tail = 1
rpm-build d9acb6
        return self._last
rpm-build d9acb6
rpm-build d9acb6
    # Python level event handlers
rpm-build d9acb6
rpm-build d9acb6
    def close(self):
rpm-build d9acb6
        u"""close(self)
rpm-build d9acb6
rpm-build d9acb6
        Flushes the builder buffers, and returns the toplevel document
rpm-build d9acb6
        element.
rpm-build d9acb6
        """
rpm-build d9acb6
        assert not self._element_stack, u"missing end tags"
rpm-build d9acb6
        assert self._last is not None, u"missing toplevel element"
rpm-build d9acb6
        return self._last
rpm-build d9acb6
rpm-build d9acb6
    def data(self, data):
rpm-build d9acb6
        u"""data(self, data)
rpm-build d9acb6
rpm-build d9acb6
        Adds text to the current element.  The value should be either an
rpm-build d9acb6
        8-bit string containing ASCII text, or a Unicode string.
rpm-build d9acb6
        """
rpm-build d9acb6
        self._handleSaxData(data)
rpm-build d9acb6
rpm-build d9acb6
    def start(self, tag, attrs, nsmap=None):
rpm-build d9acb6
        u"""start(self, tag, attrs, nsmap=None)
rpm-build d9acb6
rpm-build d9acb6
        Opens a new element.
rpm-build d9acb6
        """
rpm-build d9acb6
        if nsmap is None:
rpm-build d9acb6
            nsmap = IMMUTABLE_EMPTY_MAPPING
rpm-build d9acb6
        return self._handleSaxStart(tag, attrs, nsmap)
rpm-build d9acb6
rpm-build d9acb6
    def end(self, tag):
rpm-build d9acb6
        u"""end(self, tag)
rpm-build d9acb6
rpm-build d9acb6
        Closes the current element.
rpm-build d9acb6
        """
rpm-build d9acb6
        element = self._handleSaxEnd(tag)
rpm-build d9acb6
        assert self._last.tag == tag,\
rpm-build d9acb6
            f"end tag mismatch (expected {self._last.tag}, got {tag})"
rpm-build d9acb6
        return element
rpm-build d9acb6
rpm-build d9acb6
    def pi(self, target, data):
rpm-build d9acb6
        u"""pi(self, target, data)
rpm-build d9acb6
        """
rpm-build d9acb6
        return self._handleSaxPi(target, data)
rpm-build d9acb6
rpm-build d9acb6
    def comment(self, comment):
rpm-build d9acb6
        u"""comment(self, comment)
rpm-build d9acb6
        """
rpm-build d9acb6
        return self._handleSaxComment(comment)