1 # Copyright 2010-2023 Kurt McKee <contactme@kurtmckee.org> 2 # Copyright 2002-2008 Mark Pilgrim 3 # All rights reserved. 4 # 5 # This file is a part of feedparser. 6 # 7 # Redistribution and use in source and binary forms, with or without 8 # modification, are permitted provided that the following conditions are met: 9 # 10 # * Redistributions of source code must retain the above copyright notice, 11 # this list of conditions and the following disclaimer. 12 # * Redistributions in binary form must reproduce the above copyright notice, 13 # this list of conditions and the following disclaimer in the documentation 14 # and/or other materials provided with the distribution. 15 # 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' 17 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 # POSSIBILITY OF SUCH DAMAGE. 27 28 import re 29 30 import sgmllib 31 32 __all__ = [ 33 'sgmllib', 34 'charref', 35 'tagfind', 36 'attrfind', 37 'entityref', 38 'incomplete', 39 'interesting', 40 'shorttag', 41 'shorttagopen', 42 'starttagopen', 43 'endbracket', 44 ] 45 46 # sgmllib defines a number of module-level regular expressions that are 47 # insufficient for the XML parsing feedparser needs. Rather than modify 48 # the variables directly in sgmllib, they're defined here using the same 49 # names, and the compiled code objects of several sgmllib.SGMLParser 50 # methods are copied into _BaseHTMLProcessor so that they execute in 51 # feedparser's scope instead of sgmllib's scope. 52 charref = re.compile(r'&#(\d+|[xX][0-9a-fA-F]+);') 53 tagfind = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*') 54 attrfind = re.compile( 55 r"""\s*([a-zA-Z_][-:.a-zA-Z_0-9]*)[$]?(\s*=\s*""" 56 r"""('[^']*'|"[^"]*"|[][\-a-zA-Z0-9./,:;+*%?!&$()_#=~'"@]*))?""" 57 ) 58 59 # Unfortunately, these must be copied over to prevent NameError exceptions 60 entityref = sgmllib.entityref 61 incomplete = sgmllib.incomplete 62 interesting = sgmllib.interesting 63 shorttag = sgmllib.shorttag 64 shorttagopen = sgmllib.shorttagopen 65 starttagopen = sgmllib.starttagopen 66 67 68 class _EndBracketRegEx: 69 def __init__(self): 70 # Overriding the built-in sgmllib.endbracket regex allows the 71 # parser to find angle brackets embedded in element attributes. 72 self.endbracket = re.compile( 73 r'(' 74 r"""[^'"<>]""" 75 r"""|"[^"]*"(?=>|/|\s|\w+=)""" 76 r"""|'[^']*'(?=>|/|\s|\w+=))*(?=[<>])""" 77 r"""|.*?(?=[<>]""" 78 r')' 79 ) 80 81 def search(self, target, index=0): 82 match = self.endbracket.match(target, index) 83 if match is not None: 84 # Returning a new object in the calling thread's context 85 # resolves a thread-safety. 86 return EndBracketMatch(match) 87 return None 88 89 90 class EndBracketMatch: 91 def __init__(self, match): 92 self.match = match 93 94 def start(self, n): 95 return self.match.end(n) 96 97 98 endbracket = _EndBracketRegEx() 99